Guard against lazy initialization of idepth.
[mono-project.git] / mono / metadata / verify.c
blob8648d94623e0fab5db1223d0c660f865c6dc56f5
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 */
10 #include <config.h>
12 #include <mono/metadata/object-internals.h>
13 #include <mono/metadata/verify.h>
14 #include <mono/metadata/verify-internals.h>
15 #include <mono/metadata/opcodes.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/reflection.h>
18 #include <mono/metadata/debug-helpers.h>
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/metadata.h>
21 #include <mono/metadata/metadata-internals.h>
22 #include <mono/metadata/class-internals.h>
23 #include <mono/metadata/security-manager.h>
24 #include <mono/metadata/security-core-clr.h>
25 #include <mono/metadata/tokentype.h>
26 #include <mono/metadata/mono-basic-block.h>
27 #include <mono/utils/mono-counters.h>
28 #include <mono/utils/monobitset.h>
29 #include <string.h>
30 #include <signal.h>
31 #include <ctype.h>
33 static MiniVerifierMode verifier_mode = MONO_VERIFIER_MODE_OFF;
34 static gboolean verify_all = FALSE;
37 * Set the desired level of checks for the verfier.
40 void
41 mono_verifier_set_mode (MiniVerifierMode mode)
43 verifier_mode = mode;
46 void
47 mono_verifier_enable_verify_all ()
49 verify_all = TRUE;
52 #ifndef DISABLE_VERIFIER
54 * Pull the list of opcodes
56 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
57 a = i,
59 enum {
60 #include "mono/cil/opcode.def"
61 LAST = 0xff
63 #undef OPDEF
65 #ifdef MONO_VERIFIER_DEBUG
66 #define VERIFIER_DEBUG(code) do { code } while (0)
67 #else
68 #define VERIFIER_DEBUG(code)
69 #endif
71 //////////////////////////////////////////////////////////////////
72 #define IS_STRICT_MODE(ctx) (((ctx)->level & MONO_VERIFY_NON_STRICT) == 0)
73 #define IS_FAIL_FAST_MODE(ctx) (((ctx)->level & MONO_VERIFY_FAIL_FAST) == MONO_VERIFY_FAIL_FAST)
74 #define IS_SKIP_VISIBILITY(ctx) (((ctx)->level & MONO_VERIFY_SKIP_VISIBILITY) == MONO_VERIFY_SKIP_VISIBILITY)
75 #define IS_REPORT_ALL_ERRORS(ctx) (((ctx)->level & MONO_VERIFY_REPORT_ALL_ERRORS) == MONO_VERIFY_REPORT_ALL_ERRORS)
76 #define CLEAR_PREFIX(ctx, prefix) do { (ctx)->prefix_set &= ~(prefix); } while (0)
77 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
78 do { \
79 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
80 vinfo->info.status = __status; \
81 vinfo->info.message = ( __msg ); \
82 vinfo->exception_type = (__exception); \
83 (__ctx)->list = g_slist_prepend ((__ctx)->list, vinfo); \
84 } while (0)
86 //TODO support MONO_VERIFY_REPORT_ALL_ERRORS
87 #define ADD_VERIFY_ERROR(__ctx, __msg) \
88 do { \
89 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
90 (__ctx)->valid = 0; \
91 } while (0)
93 #define CODE_NOT_VERIFIABLE(__ctx, __msg) \
94 do { \
95 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
96 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, MONO_EXCEPTION_UNVERIFIABLE_IL); \
97 (__ctx)->verifiable = 0; \
98 if (IS_FAIL_FAST_MODE (__ctx)) \
99 (__ctx)->valid = 0; \
101 } while (0)
103 #define ADD_VERIFY_ERROR2(__ctx, __msg, __exception) \
104 do { \
105 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, __exception); \
106 (__ctx)->valid = 0; \
107 } while (0)
109 #define CODE_NOT_VERIFIABLE2(__ctx, __msg, __exception) \
110 do { \
111 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
112 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, __exception); \
113 (__ctx)->verifiable = 0; \
114 if (IS_FAIL_FAST_MODE (__ctx)) \
115 (__ctx)->valid = 0; \
117 } while (0)
119 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
120 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
122 #if SIZEOF_VOID_P == 4
123 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
124 #else
125 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
126 #endif
128 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
129 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
131 /*Flags to be used with ILCodeDesc::flags */
132 enum {
133 /*Instruction has not been processed.*/
134 IL_CODE_FLAG_NOT_PROCESSED = 0,
135 /*Instruction was decoded by mono_method_verify loop.*/
136 IL_CODE_FLAG_SEEN = 1,
137 /*Instruction was target of a branch or is at a protected block boundary.*/
138 IL_CODE_FLAG_WAS_TARGET = 2,
139 /*Used by stack_init to avoid double initialize each entry.*/
140 IL_CODE_FLAG_STACK_INITED = 4,
141 /*Used by merge_stacks to decide if it should just copy the eval stack.*/
142 IL_CODE_STACK_MERGED = 8,
143 /*This instruction is part of the delegate construction sequence, it cannot be target of a branch.*/
144 IL_CODE_DELEGATE_SEQUENCE = 0x10,
145 /*This is a delegate created from a ldftn to a non final virtual method*/
146 IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL = 0x20,
147 /*This is a call to a non final virtual method*/
148 IL_CODE_CALL_NONFINAL_VIRTUAL = 0x40,
151 typedef enum {
152 RESULT_VALID,
153 RESULT_UNVERIFIABLE,
154 RESULT_INVALID
155 } verify_result_t;
157 typedef struct {
158 MonoType *type;
159 int stype;
160 MonoMethod *method;
161 } ILStackDesc;
164 typedef struct {
165 ILStackDesc *stack;
166 guint16 size, max_size;
167 guint16 flags;
168 } ILCodeDesc;
170 typedef struct {
171 int max_args;
172 int max_stack;
173 int verifiable;
174 int valid;
175 int level;
177 int code_size;
178 ILCodeDesc *code;
179 ILCodeDesc eval;
181 MonoType **params;
182 GSList *list;
183 /*Allocated fnptr MonoType that should be freed by us.*/
184 GSList *funptrs;
185 /*Type dup'ed exception types from catch blocks.*/
186 GSList *exception_types;
188 int num_locals;
189 MonoType **locals;
191 /*TODO get rid of target here, need_merge in mono_method_verify and hoist the merging code in the branching code*/
192 int target;
194 guint32 ip_offset;
195 MonoMethodSignature *signature;
196 MonoMethodHeader *header;
198 MonoGenericContext *generic_context;
199 MonoImage *image;
200 MonoMethod *method;
202 /*This flag helps solving a corner case of delegate verification in that you cannot have a "starg 0"
203 *on a method that creates a delegate for a non-final virtual method using ldftn*/
204 gboolean has_this_store;
206 /*This flag is used to control if the contructor of the parent class has been called.
207 *If the this pointer is pushed on the eval stack and it's a reference type constructor and
208 * super_ctor_called is false, the uninitialized flag is set on the pushed value.
210 * Poping an uninitialized this ptr from the eval stack is an unverifiable operation unless
211 * the safe variant is used. Only a few opcodes can use it : dup, pop, ldfld, stfld and call to a constructor.
213 gboolean super_ctor_called;
215 guint32 prefix_set;
216 gboolean has_flags;
217 MonoType *constrained_type;
218 } VerifyContext;
220 static void
221 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external);
223 static int
224 get_stack_type (MonoType *type);
226 static gboolean
227 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn);
229 static gboolean
230 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass);
232 static gboolean
233 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method);
235 static MonoGenericParam*
236 verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type);
238 static gboolean
239 verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate);
240 //////////////////////////////////////////////////////////////////
244 enum {
245 TYPE_INV = 0, /* leave at 0. */
246 TYPE_I4 = 1,
247 TYPE_I8 = 2,
248 TYPE_NATIVE_INT = 3,
249 TYPE_R8 = 4,
250 /* Used by operator tables to resolve pointer types (managed & unmanaged) and by unmanaged pointer types*/
251 TYPE_PTR = 5,
252 /* value types and classes */
253 TYPE_COMPLEX = 6,
254 /* Number of types, used to define the size of the tables*/
255 TYPE_MAX = 6,
257 /* Used by tables to signal that a result is not verifiable*/
258 NON_VERIFIABLE_RESULT = 0x80,
260 /*Mask used to extract just the type, excluding flags */
261 TYPE_MASK = 0x0F,
263 /* The stack type is a managed pointer, unmask the value to res */
264 POINTER_MASK = 0x100,
266 /*Stack type with the pointer mask*/
267 RAW_TYPE_MASK = 0x10F,
269 /* Controlled Mutability Manager Pointer */
270 CMMP_MASK = 0x200,
272 /* The stack type is a null literal*/
273 NULL_LITERAL_MASK = 0x400,
275 /**Used by ldarg.0 and family to let delegate verification happens.*/
276 THIS_POINTER_MASK = 0x800,
278 /**Signals that this is a boxed value type*/
279 BOXED_MASK = 0x1000,
281 /*This is an unitialized this ref*/
282 UNINIT_THIS_MASK = 0x2000,
285 static const char* const
286 type_names [TYPE_MAX + 1] = {
287 "Invalid",
288 "Int32",
289 "Int64",
290 "Native Int",
291 "Float64",
292 "Native Pointer",
293 "Complex"
296 enum {
297 PREFIX_UNALIGNED = 1,
298 PREFIX_VOLATILE = 2,
299 PREFIX_TAIL = 4,
300 PREFIX_CONSTRAINED = 8,
301 PREFIX_READONLY = 16
303 //////////////////////////////////////////////////////////////////
305 #ifdef ENABLE_VERIFIER_STATS
307 #define MEM_ALLOC(amt) do { allocated_memory += (amt); working_set += (amt); } while (0)
308 #define MEM_FREE(amt) do { working_set -= (amt); } while (0)
310 static int allocated_memory;
311 static int working_set;
312 static int max_allocated_memory;
313 static int max_working_set;
314 static int total_allocated_memory;
316 static void
317 finish_collect_stats (void)
319 max_allocated_memory = MAX (max_allocated_memory, allocated_memory);
320 max_working_set = MAX (max_working_set, working_set);
321 total_allocated_memory += allocated_memory;
322 allocated_memory = working_set = 0;
325 static void
326 init_verifier_stats (void)
328 static gboolean inited;
329 if (!inited) {
330 inited = TRUE;
331 mono_counters_register ("Maximum memory allocated during verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &max_allocated_memory);
332 mono_counters_register ("Maximum memory used during verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &max_working_set);
333 mono_counters_register ("Total memory allocated for verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &total_allocated_memory);
337 #else
339 #define MEM_ALLOC(amt) do {} while (0)
340 #define MEM_FREE(amt) do { } while (0)
342 #define finish_collect_stats()
343 #define init_verifier_stats()
345 #endif
348 //////////////////////////////////////////////////////////////////
351 /*Token validation macros and functions */
352 #define IS_MEMBER_REF(token) (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
353 #define IS_METHOD_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
354 #define IS_METHOD_SPEC(token) (mono_metadata_token_table (token) == MONO_TABLE_METHODSPEC)
355 #define IS_FIELD_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_FIELD)
357 #define IS_TYPE_REF(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPEREF)
358 #define IS_TYPE_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPEDEF)
359 #define IS_TYPE_SPEC(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC)
360 #define IS_METHOD_DEF_OR_REF_OR_SPEC(token) (IS_METHOD_DEF (token) || IS_MEMBER_REF (token) || IS_METHOD_SPEC (token))
361 #define IS_TYPE_DEF_OR_REF_OR_SPEC(token) (IS_TYPE_DEF (token) || IS_TYPE_REF (token) || IS_TYPE_SPEC (token))
362 #define IS_FIELD_DEF_OR_REF(token) (IS_FIELD_DEF (token) || IS_MEMBER_REF (token))
365 * Verify if @token refers to a valid row on int's table.
367 static gboolean
368 token_bounds_check (MonoImage *image, guint32 token)
370 if (image->dynamic)
371 return mono_reflection_is_valid_dynamic_token ((MonoDynamicImage*)image, token);
372 return image->tables [mono_metadata_token_table (token)].rows >= mono_metadata_token_index (token) && mono_metadata_token_index (token) > 0;
375 static MonoType *
376 mono_type_create_fnptr_from_mono_method (VerifyContext *ctx, MonoMethod *method)
378 MonoType *res = g_new0 (MonoType, 1);
379 MEM_ALLOC (sizeof (MonoType));
381 //FIXME use mono_method_get_signature_full
382 res->data.method = mono_method_signature (method);
383 res->type = MONO_TYPE_FNPTR;
384 ctx->funptrs = g_slist_prepend (ctx->funptrs, res);
385 return res;
389 * mono_type_is_enum_type:
391 * Returns TRUE if @type is an enum type.
393 static gboolean
394 mono_type_is_enum_type (MonoType *type)
396 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)
397 return TRUE;
398 if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype)
399 return TRUE;
400 return FALSE;
404 * mono_type_is_value_type:
406 * Returns TRUE if @type is named after @namespace.@name.
409 static gboolean
410 mono_type_is_value_type (MonoType *type, const char *namespace, const char *name)
412 return type->type == MONO_TYPE_VALUETYPE &&
413 !strcmp (namespace, type->data.klass->name_space) &&
414 !strcmp (name, type->data.klass->name);
418 * Returns TURE if @type is VAR or MVAR
420 static gboolean
421 mono_type_is_generic_argument (MonoType *type)
423 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
427 * mono_type_get_underlying_type_any:
429 * This functions is just like mono_type_get_underlying_type but it doesn't care if the type is byref.
431 * Returns the underlying type of @type regardless if it is byref or not.
433 static MonoType*
434 mono_type_get_underlying_type_any (MonoType *type)
436 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)
437 return mono_class_enum_basetype (type->data.klass);
438 if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype)
439 return mono_class_enum_basetype (type->data.generic_class->container_class);
440 return type;
443 static G_GNUC_UNUSED const char*
444 mono_type_get_stack_name (MonoType *type)
446 return type_names [get_stack_type (type) & TYPE_MASK];
449 #define CTOR_REQUIRED_FLAGS (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_RT_SPECIAL_NAME)
450 #define CTOR_INVALID_FLAGS (METHOD_ATTRIBUTE_STATIC)
452 static gboolean
453 mono_method_is_constructor (MonoMethod *method)
455 return ((method->flags & CTOR_REQUIRED_FLAGS) == CTOR_REQUIRED_FLAGS &&
456 !(method->flags & CTOR_INVALID_FLAGS) &&
457 !strcmp (".ctor", method->name));
460 static gboolean
461 mono_class_has_default_constructor (MonoClass *klass)
463 MonoMethod *method;
464 int i;
466 mono_class_setup_methods (klass);
467 if (klass->exception_type)
468 return FALSE;
470 for (i = 0; i < klass->method.count; ++i) {
471 method = klass->methods [i];
472 if (mono_method_is_constructor (method) &&
473 mono_method_signature (method) &&
474 mono_method_signature (method)->param_count == 0 &&
475 (method->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC)
476 return TRUE;
478 return FALSE;
482 * Verify if @type is valid for the given @ctx verification context.
483 * this function checks for VAR and MVAR types that are invalid under the current verifier,
485 static gboolean
486 mono_type_is_valid_type_in_context_full (MonoType *type, MonoGenericContext *context, gboolean check_gtd)
488 int i;
489 MonoGenericInst *inst;
491 switch (type->type) {
492 case MONO_TYPE_VAR:
493 case MONO_TYPE_MVAR:
494 if (!context)
495 return FALSE;
496 inst = type->type == MONO_TYPE_VAR ? context->class_inst : context->method_inst;
497 if (!inst || mono_type_get_generic_param_num (type) >= inst->type_argc)
498 return FALSE;
499 break;
500 case MONO_TYPE_SZARRAY:
501 return mono_type_is_valid_type_in_context_full (&type->data.klass->byval_arg, context, check_gtd);
502 case MONO_TYPE_ARRAY:
503 return mono_type_is_valid_type_in_context_full (&type->data.array->eklass->byval_arg, context, check_gtd);
504 case MONO_TYPE_PTR:
505 return mono_type_is_valid_type_in_context_full (type->data.type, context, check_gtd);
506 case MONO_TYPE_GENERICINST:
507 inst = type->data.generic_class->context.class_inst;
508 if (!inst->is_open)
509 break;
510 for (i = 0; i < inst->type_argc; ++i)
511 if (!mono_type_is_valid_type_in_context_full (inst->type_argv [i], context, check_gtd))
512 return FALSE;
513 break;
514 case MONO_TYPE_CLASS:
515 case MONO_TYPE_VALUETYPE: {
516 MonoClass *klass = type->data.klass;
518 * It's possible to encode generic'sh types in such a way that they disguise themselves as class or valuetype.
519 * Fixing the type decoding is really tricky since under some cases this behavior is needed, for example, to
520 * have a 'class' type pointing to a 'genericinst' class.
522 * For the runtime these non canonical (weird) encodings work fine, they worst they can cause is some
523 * reflection oddities which are harmless - to security at least.
525 if (klass->byval_arg.type != type->type)
526 return mono_type_is_valid_type_in_context_full (&klass->byval_arg, context, check_gtd);
528 if (check_gtd && klass->generic_container)
529 return FALSE;
530 break;
533 return TRUE;
536 static gboolean
537 mono_type_is_valid_type_in_context (MonoType *type, MonoGenericContext *context)
539 return mono_type_is_valid_type_in_context_full (type, context, FALSE);
542 /*This function returns NULL if the type is not instantiatable*/
543 static MonoType*
544 verifier_inflate_type (VerifyContext *ctx, MonoType *type, MonoGenericContext *context)
546 MonoError error;
547 MonoType *result;
549 result = mono_class_inflate_generic_type_checked (type, context, &error);
550 if (!mono_error_ok (&error)) {
551 mono_error_cleanup (&error);
552 return NULL;
554 return result;
557 /*A side note here. We don't need to check if arguments are broken since this
558 is only need to be done by the runtime before realizing the type.
560 static gboolean
561 is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
563 MonoError error;
564 int i;
566 if (ginst->type_argc != gc->type_argc)
567 return FALSE;
569 for (i = 0; i < gc->type_argc; ++i) {
570 MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
571 MonoClass *paramClass;
572 MonoClass **constraints;
573 MonoType *param_type = ginst->type_argv [i];
575 /*it's not our job to validate type variables*/
576 if (mono_type_is_generic_argument (param_type))
577 continue;
579 paramClass = mono_class_from_mono_type (param_type);
582 /* A GTD can't be a generic argument.
584 * Due to how types are encoded we must check for the case of a genericinst MonoType and GTD MonoClass.
585 * This happens in cases such as: class Foo<T> { void X() { new Bar<T> (); } }
587 * Open instantiations can have GTDs as this happens when one type is instantiated with others params
588 * and the former has an expansion into the later. For example:
589 * class B<K> {}
590 * class A<T>: B<K> {}
591 * The type A <K> has a parent B<K>, that is inflated into the GTD B<>.
592 * Since A<K> is open, thus not instantiatable, this is valid.
594 if (paramClass->generic_container && param_type->type != MONO_TYPE_GENERICINST && !ginst->is_open)
595 return FALSE;
597 /*it's not safe to call mono_class_init from here*/
598 if (paramClass->generic_class && !paramClass->inited) {
599 if (!mono_class_is_valid_generic_instantiation (NULL, paramClass))
600 return FALSE;
603 if (!param_info->constraints && !(param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK))
604 continue;
606 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && (!paramClass->valuetype || mono_class_is_nullable (paramClass)))
607 return FALSE;
609 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && paramClass->valuetype)
610 return FALSE;
612 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !paramClass->valuetype && !mono_class_has_default_constructor (paramClass))
613 return FALSE;
615 if (!param_info->constraints)
616 continue;
618 for (constraints = param_info->constraints; *constraints; ++constraints) {
619 MonoClass *ctr = *constraints;
620 MonoType *inflated;
622 inflated = mono_class_inflate_generic_type_checked (&ctr->byval_arg, context, &error);
623 if (!mono_error_ok (&error)) {
624 mono_error_cleanup (&error);
625 return FALSE;
627 ctr = mono_class_from_mono_type (inflated);
628 mono_metadata_free_type (inflated);
630 /*FIXME maybe we need the same this as verifier_class_is_assignable_from*/
631 if (!mono_class_is_assignable_from_slow (ctr, paramClass))
632 return FALSE;
635 return TRUE;
639 * Return true if @candidate is constraint compatible with @target.
641 * This means that @candidate constraints are a super set of @target constaints
643 static gboolean
644 mono_generic_param_is_constraint_compatible (VerifyContext *ctx, MonoGenericParam *target, MonoGenericParam *candidate, MonoClass *candidate_param_class, MonoGenericContext *context)
646 MonoGenericParamInfo *tinfo = mono_generic_param_info (target);
647 MonoGenericParamInfo *cinfo = mono_generic_param_info (candidate);
649 int tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
650 int cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
651 if ((tmask & cmask) != tmask)
652 return FALSE;
654 if (tinfo->constraints) {
655 MonoClass **target_class, **candidate_class;
656 for (target_class = tinfo->constraints; *target_class; ++target_class) {
657 MonoClass *tc;
658 MonoType *inflated = verifier_inflate_type (ctx, &(*target_class)->byval_arg, context);
659 if (!inflated)
660 return FALSE;
661 tc = mono_class_from_mono_type (inflated);
662 mono_metadata_free_type (inflated);
665 * A constraint from @target might inflate into @candidate itself and in that case we don't need
666 * check it's constraints since it satisfy the constraint by itself.
668 if (mono_metadata_type_equal (&tc->byval_arg, &candidate_param_class->byval_arg))
669 continue;
671 if (!cinfo->constraints)
672 return FALSE;
674 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
675 MonoClass *cc;
676 inflated = verifier_inflate_type (ctx, &(*candidate_class)->byval_arg, ctx->generic_context);
677 if (!inflated)
678 return FALSE;
679 cc = mono_class_from_mono_type (inflated);
680 mono_metadata_free_type (inflated);
682 if (verifier_class_is_assignable_from (tc, cc))
683 break;
686 * This happens when we have the following:
688 * Bar<K> where K : IFace
689 * Foo<T, U> where T : U where U : IFace
690 * ...
691 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
694 if (mono_type_is_generic_argument (&cc->byval_arg)) {
695 MonoGenericParam *other_candidate = verifier_get_generic_param_from_type (ctx, &cc->byval_arg);
697 if (mono_generic_param_is_constraint_compatible (ctx, target, other_candidate, cc, context)) {
698 break;
702 if (!*candidate_class)
703 return FALSE;
706 return TRUE;
709 static MonoGenericParam*
710 verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type)
712 MonoGenericContainer *gc;
713 MonoMethod *method = ctx->method;
714 int num;
716 num = mono_type_get_generic_param_num (type);
718 if (type->type == MONO_TYPE_VAR) {
719 MonoClass *gtd = method->klass;
720 if (gtd->generic_class)
721 gtd = gtd->generic_class->container_class;
722 gc = gtd->generic_container;
723 } else { //MVAR
724 MonoMethod *gmd = method;
725 if (method->is_inflated)
726 gmd = ((MonoMethodInflated*)method)->declaring;
727 gc = mono_method_get_generic_container (gmd);
729 if (!gc)
730 return NULL;
731 return mono_generic_container_get_param (gc, num);
737 * Verify if @type is valid for the given @ctx verification context.
738 * this function checks for VAR and MVAR types that are invalid under the current verifier,
739 * This means that it either
741 static gboolean
742 is_valid_type_in_context (VerifyContext *ctx, MonoType *type)
744 return mono_type_is_valid_type_in_context (type, ctx->generic_context);
747 static gboolean
748 is_valid_generic_instantiation_in_context (VerifyContext *ctx, MonoGenericInst *ginst)
750 int i;
751 for (i = 0; i < ginst->type_argc; ++i) {
752 MonoType *type = ginst->type_argv [i];
753 if (!is_valid_type_in_context (ctx, type))
754 return FALSE;
756 return TRUE;
759 static gboolean
760 generic_arguments_respect_constraints (VerifyContext *ctx, MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
762 int i;
763 for (i = 0; i < ginst->type_argc; ++i) {
764 MonoType *type = ginst->type_argv [i];
765 MonoGenericParam *target = mono_generic_container_get_param (gc, i);
766 MonoGenericParam *candidate;
767 MonoClass *candidate_class;
769 if (!mono_type_is_generic_argument (type))
770 continue;
772 if (!is_valid_type_in_context (ctx, type))
773 return FALSE;
775 candidate = verifier_get_generic_param_from_type (ctx, type);
776 candidate_class = mono_class_from_mono_type (type);
778 if (!mono_generic_param_is_constraint_compatible (ctx, target, candidate, candidate_class, context))
779 return FALSE;
781 return TRUE;
784 static gboolean
785 mono_method_repect_method_constraints (VerifyContext *ctx, MonoMethod *method)
787 MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
788 MonoGenericInst *ginst = gmethod->context.method_inst;
789 MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
790 return !gc || generic_arguments_respect_constraints (ctx, gc, &gmethod->context, ginst);
793 static gboolean
794 mono_class_repect_method_constraints (VerifyContext *ctx, MonoClass *klass)
796 MonoGenericClass *gklass = klass->generic_class;
797 MonoGenericInst *ginst = gklass->context.class_inst;
798 MonoGenericContainer *gc = gklass->container_class->generic_container;
799 return !gc || generic_arguments_respect_constraints (ctx, gc, &gklass->context, ginst);
802 static gboolean
803 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method)
805 MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
806 MonoGenericInst *ginst = gmethod->context.method_inst;
807 MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
808 if (!gc) /*non-generic inflated method - it's part of a generic type */
809 return TRUE;
810 if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst))
811 return FALSE;
812 return is_valid_generic_instantiation (gc, &gmethod->context, ginst);
816 static gboolean
817 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass)
819 MonoGenericClass *gklass = klass->generic_class;
820 MonoGenericInst *ginst = gklass->context.class_inst;
821 MonoGenericContainer *gc = gklass->container_class->generic_container;
822 if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst))
823 return FALSE;
824 return is_valid_generic_instantiation (gc, &gklass->context, ginst);
827 static gboolean
828 mono_type_is_valid_in_context (VerifyContext *ctx, MonoType *type)
830 MonoClass *klass;
832 if (type == NULL) {
833 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid null type at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
834 return FALSE;
837 if (!is_valid_type_in_context (ctx, type)) {
838 char *str = mono_type_full_name (type);
839 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type (%s%s) (argument out of range or %s is not generic) at 0x%04x",
840 type->type == MONO_TYPE_VAR ? "!" : "!!",
841 str,
842 type->type == MONO_TYPE_VAR ? "class" : "method",
843 ctx->ip_offset),
844 MONO_EXCEPTION_BAD_IMAGE);
845 g_free (str);
846 return FALSE;
849 klass = mono_class_from_mono_type (type);
850 mono_class_init (klass);
851 if (mono_loader_get_last_error () || klass->exception_type != MONO_EXCEPTION_NONE) {
852 if (klass->generic_class && !mono_class_is_valid_generic_instantiation (NULL, klass))
853 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);
854 else
855 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);
856 mono_loader_clear_error ();
857 return FALSE;
860 if (klass->generic_class && klass->generic_class->container_class->exception_type != MONO_EXCEPTION_NONE) {
861 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);
862 return FALSE;
865 if (!klass->generic_class)
866 return TRUE;
868 if (!mono_class_is_valid_generic_instantiation (ctx, klass)) {
869 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);
870 return FALSE;
873 if (!mono_class_repect_method_constraints (ctx, klass)) {
874 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);
875 return FALSE;
878 return TRUE;
881 static verify_result_t
882 mono_method_is_valid_in_context (VerifyContext *ctx, MonoMethod *method)
884 if (!mono_type_is_valid_in_context (ctx, &method->klass->byval_arg))
885 return RESULT_INVALID;
887 if (!method->is_inflated)
888 return RESULT_VALID;
890 if (!mono_method_is_valid_generic_instantiation (ctx, method)) {
891 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);
892 return RESULT_INVALID;
895 if (!mono_method_repect_method_constraints (ctx, method)) {
896 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));
897 return RESULT_UNVERIFIABLE;
899 return RESULT_VALID;
903 static MonoClassField*
904 verifier_load_field (VerifyContext *ctx, int token, MonoClass **out_klass, const char *opcode) {
905 MonoClassField *field;
906 MonoClass *klass = NULL;
908 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
909 field = mono_method_get_wrapper_data (ctx->method, (guint32)token);
910 klass = field ? field->parent : NULL;
911 } else {
912 if (!IS_FIELD_DEF_OR_REF (token) || !token_bounds_check (ctx->image, token)) {
913 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);
914 return NULL;
917 field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context);
920 if (!field || !field->parent || !klass || mono_loader_get_last_error ()) {
921 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);
922 mono_loader_clear_error ();
923 return NULL;
926 if (!mono_type_is_valid_in_context (ctx, &klass->byval_arg))
927 return NULL;
929 if (mono_field_get_flags (field) & FIELD_ATTRIBUTE_LITERAL) {
930 char *type_name = mono_type_get_full_name (field->parent);
931 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot reference literal field %s::%s at 0x%04x", type_name, field->name, ctx->ip_offset));
932 g_free (type_name);
933 return NULL;
936 *out_klass = klass;
937 return field;
940 static MonoMethod*
941 verifier_load_method (VerifyContext *ctx, int token, const char *opcode) {
942 MonoMethod* method;
944 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
945 method = mono_method_get_wrapper_data (ctx->method, (guint32)token);
946 } else {
947 if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
948 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);
949 return NULL;
952 method = mono_get_method_full (ctx->image, token, NULL, ctx->generic_context);
955 if (!method || mono_loader_get_last_error ()) {
956 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);
957 mono_loader_clear_error ();
958 return NULL;
961 if (mono_method_is_valid_in_context (ctx, method) == RESULT_INVALID)
962 return NULL;
964 return method;
967 static MonoType*
968 verifier_load_type (VerifyContext *ctx, int token, const char *opcode) {
969 MonoType* type;
971 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
972 MonoClass *class = mono_method_get_wrapper_data (ctx->method, (guint32)token);
973 type = class ? &class->byval_arg : NULL;
974 } else {
975 if (!IS_TYPE_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
976 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid type token 0x%08x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
977 return NULL;
979 type = mono_type_get_full (ctx->image, token, ctx->generic_context);
982 if (!type || mono_loader_get_last_error ()) {
983 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);
984 mono_loader_clear_error ();
985 return NULL;
988 if (!mono_type_is_valid_in_context (ctx, type))
989 return NULL;
991 return type;
995 /* stack_slot_get_type:
997 * Returns the stack type of @value. This value includes POINTER_MASK.
999 * Use this function to checks that account for a managed pointer.
1001 static gint32
1002 stack_slot_get_type (ILStackDesc *value)
1004 return value->stype & RAW_TYPE_MASK;
1007 /* stack_slot_get_underlying_type:
1009 * Returns the stack type of @value. This value does not include POINTER_MASK.
1011 * Use this function is cases where the fact that the value could be a managed pointer is
1012 * irrelevant. For example, field load doesn't care about this fact of type on stack.
1014 static gint32
1015 stack_slot_get_underlying_type (ILStackDesc *value)
1017 return value->stype & TYPE_MASK;
1020 /* stack_slot_is_managed_pointer:
1022 * Returns TRUE is @value is a managed pointer.
1024 static gboolean
1025 stack_slot_is_managed_pointer (ILStackDesc *value)
1027 return (value->stype & POINTER_MASK) == POINTER_MASK;
1030 /* stack_slot_is_managed_mutability_pointer:
1032 * Returns TRUE is @value is a managed mutability pointer.
1034 static G_GNUC_UNUSED gboolean
1035 stack_slot_is_managed_mutability_pointer (ILStackDesc *value)
1037 return (value->stype & CMMP_MASK) == CMMP_MASK;
1040 /* stack_slot_is_null_literal:
1042 * Returns TRUE is @value is the null literal.
1044 static gboolean
1045 stack_slot_is_null_literal (ILStackDesc *value)
1047 return (value->stype & NULL_LITERAL_MASK) == NULL_LITERAL_MASK;
1051 /* stack_slot_is_this_pointer:
1053 * Returns TRUE is @value is the this literal
1055 static gboolean
1056 stack_slot_is_this_pointer (ILStackDesc *value)
1058 return (value->stype & THIS_POINTER_MASK) == THIS_POINTER_MASK;
1061 /* stack_slot_is_boxed_value:
1063 * Returns TRUE is @value is a boxed value
1065 static gboolean
1066 stack_slot_is_boxed_value (ILStackDesc *value)
1068 return (value->stype & BOXED_MASK) == BOXED_MASK;
1071 static const char *
1072 stack_slot_get_name (ILStackDesc *value)
1074 return type_names [value->stype & TYPE_MASK];
1077 #define APPEND_WITH_PREDICATE(PRED,NAME) do {\
1078 if (PRED (value)) { \
1079 if (!first) \
1080 g_string_append (str, ", "); \
1081 g_string_append (str, NAME); \
1082 first = FALSE; \
1083 } } while (0)
1085 static char*
1086 stack_slot_stack_type_full_name (ILStackDesc *value)
1088 GString *str = g_string_new ("");
1089 char *result;
1090 gboolean has_pred = FALSE, first = TRUE;
1092 if ((value->stype & TYPE_MASK) != value->stype) {
1093 g_string_append(str, "[");
1094 APPEND_WITH_PREDICATE (stack_slot_is_this_pointer, "this");
1095 APPEND_WITH_PREDICATE (stack_slot_is_boxed_value, "boxed");
1096 APPEND_WITH_PREDICATE (stack_slot_is_null_literal, "null");
1097 APPEND_WITH_PREDICATE (stack_slot_is_managed_mutability_pointer, "cmmp");
1098 APPEND_WITH_PREDICATE (stack_slot_is_managed_pointer, "mp");
1099 has_pred = TRUE;
1102 if (mono_type_is_generic_argument (value->type) && !stack_slot_is_boxed_value (value)) {
1103 if (!has_pred)
1104 g_string_append(str, "[");
1105 if (!first)
1106 g_string_append (str, ", ");
1107 g_string_append (str, "unboxed");
1108 has_pred = TRUE;
1111 if (has_pred)
1112 g_string_append(str, "] ");
1114 g_string_append (str, stack_slot_get_name (value));
1115 result = str->str;
1116 g_string_free (str, FALSE);
1117 return result;
1120 static char*
1121 stack_slot_full_name (ILStackDesc *value)
1123 char *type_name = mono_type_full_name (value->type);
1124 char *stack_name = stack_slot_stack_type_full_name (value);
1125 char *res = g_strdup_printf ("%s (%s)", type_name, stack_name);
1126 g_free (type_name);
1127 g_free (stack_name);
1128 return res;
1131 //////////////////////////////////////////////////////////////////
1132 void
1133 mono_free_verify_list (GSList *list)
1135 MonoVerifyInfoExtended *info;
1136 GSList *tmp;
1138 for (tmp = list; tmp; tmp = tmp->next) {
1139 info = tmp->data;
1140 g_free (info->info.message);
1141 g_free (info);
1143 g_slist_free (list);
1146 #define ADD_ERROR(list,msg) \
1147 do { \
1148 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1149 vinfo->info.status = MONO_VERIFY_ERROR; \
1150 vinfo->info.message = (msg); \
1151 (list) = g_slist_prepend ((list), vinfo); \
1152 } while (0)
1154 #define ADD_WARN(list,code,msg) \
1155 do { \
1156 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1157 vinfo->info.status = (code); \
1158 vinfo->info.message = (msg); \
1159 (list) = g_slist_prepend ((list), vinfo); \
1160 } while (0)
1162 #define ADD_INVALID(list,msg) \
1163 do { \
1164 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1165 vinfo->status = MONO_VERIFY_ERROR; \
1166 vinfo->message = (msg); \
1167 (list) = g_slist_prepend ((list), vinfo); \
1168 /*G_BREAKPOINT ();*/ \
1169 goto invalid_cil; \
1170 } while (0)
1172 #define CHECK_STACK_UNDERFLOW(num) \
1173 do { \
1174 if (cur_stack < (num)) \
1175 ADD_INVALID (list, g_strdup_printf ("Stack underflow at 0x%04x (%d items instead of %d)", ip_offset, cur_stack, (num))); \
1176 } while (0)
1178 #define CHECK_STACK_OVERFLOW() \
1179 do { \
1180 if (cur_stack >= max_stack) \
1181 ADD_INVALID (list, g_strdup_printf ("Maxstack exceeded at 0x%04x", ip_offset)); \
1182 } while (0)
1185 static int
1186 in_any_block (MonoMethodHeader *header, guint offset)
1188 int i;
1189 MonoExceptionClause *clause;
1191 for (i = 0; i < header->num_clauses; ++i) {
1192 clause = &header->clauses [i];
1193 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1194 return 1;
1195 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1196 return 1;
1197 if (MONO_OFFSET_IN_FILTER (clause, offset))
1198 return 1;
1200 return 0;
1204 * in_any_exception_block:
1206 * Returns TRUE is @offset is part of any exception clause (filter, handler, catch, finally or fault).
1208 static gboolean
1209 in_any_exception_block (MonoMethodHeader *header, guint offset)
1211 int i;
1212 MonoExceptionClause *clause;
1214 for (i = 0; i < header->num_clauses; ++i) {
1215 clause = &header->clauses [i];
1216 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1217 return TRUE;
1218 if (MONO_OFFSET_IN_FILTER (clause, offset))
1219 return TRUE;
1221 return FALSE;
1225 * is_valid_branch_instruction:
1227 * Verify if it's valid to perform a branch from @offset to @target.
1228 * This should be used with br and brtrue/false.
1229 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1230 * The major diferent from other similiar functions is that branching into a
1231 * finally/fault block is invalid instead of just unverifiable.
1233 static int
1234 is_valid_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1236 int i;
1237 MonoExceptionClause *clause;
1239 for (i = 0; i < header->num_clauses; ++i) {
1240 clause = &header->clauses [i];
1241 /*branching into a finally block is invalid*/
1242 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) &&
1243 !MONO_OFFSET_IN_HANDLER (clause, offset) &&
1244 MONO_OFFSET_IN_HANDLER (clause, target))
1245 return 2;
1247 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1248 return 1;
1249 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1250 return 1;
1251 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1252 return 1;
1254 return 0;
1258 * is_valid_cmp_branch_instruction:
1260 * Verify if it's valid to perform a branch from @offset to @target.
1261 * This should be used with binary comparison branching instruction, like beq, bge and similars.
1262 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1264 * The major diferences from other similar functions are that most errors lead to invalid
1265 * code and only branching out of finally, filter or fault clauses is unverifiable.
1267 static int
1268 is_valid_cmp_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 out of a handler or finally*/
1276 if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE &&
1277 MONO_OFFSET_IN_HANDLER (clause, offset) &&
1278 !MONO_OFFSET_IN_HANDLER (clause, target))
1279 return 1;
1281 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1282 return 2;
1283 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1284 return 2;
1285 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1286 return 2;
1288 return 0;
1292 * A leave can't escape a finally block
1294 static int
1295 is_correct_leave (MonoMethodHeader *header, guint offset, guint target)
1297 int i;
1298 MonoExceptionClause *clause;
1300 for (i = 0; i < header->num_clauses; ++i) {
1301 clause = &header->clauses [i];
1302 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY && MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
1303 return 0;
1304 if (MONO_OFFSET_IN_FILTER (clause, offset))
1305 return 0;
1307 return 1;
1311 * A rethrow can't happen outside of a catch handler.
1313 static int
1314 is_correct_rethrow (MonoMethodHeader *header, guint offset)
1316 int i;
1317 MonoExceptionClause *clause;
1319 for (i = 0; i < header->num_clauses; ++i) {
1320 clause = &header->clauses [i];
1321 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1322 return 1;
1323 if (MONO_OFFSET_IN_FILTER (clause, offset))
1324 return 1;
1326 return 0;
1330 * An endfinally can't happen outside of a finally/fault handler.
1332 static int
1333 is_correct_endfinally (MonoMethodHeader *header, guint offset)
1335 int i;
1336 MonoExceptionClause *clause;
1338 for (i = 0; i < header->num_clauses; ++i) {
1339 clause = &header->clauses [i];
1340 if (MONO_OFFSET_IN_HANDLER (clause, offset) && (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY))
1341 return 1;
1343 return 0;
1348 * An endfilter can only happens inside a filter clause.
1349 * In non-strict mode filter is allowed inside the handler clause too
1351 static MonoExceptionClause *
1352 is_correct_endfilter (VerifyContext *ctx, guint offset)
1354 int i;
1355 MonoExceptionClause *clause;
1357 for (i = 0; i < ctx->header->num_clauses; ++i) {
1358 clause = &ctx->header->clauses [i];
1359 if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER)
1360 continue;
1361 if (MONO_OFFSET_IN_FILTER (clause, offset))
1362 return clause;
1363 if (!IS_STRICT_MODE (ctx) && MONO_OFFSET_IN_HANDLER (clause, offset))
1364 return clause;
1366 return NULL;
1371 * Non-strict endfilter can happens inside a try block or any handler block
1373 static int
1374 is_unverifiable_endfilter (VerifyContext *ctx, guint offset)
1376 int i;
1377 MonoExceptionClause *clause;
1379 for (i = 0; i < ctx->header->num_clauses; ++i) {
1380 clause = &ctx->header->clauses [i];
1381 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1382 return 1;
1384 return 0;
1387 static gboolean
1388 is_valid_bool_arg (ILStackDesc *arg)
1390 if (stack_slot_is_managed_pointer (arg) || stack_slot_is_boxed_value (arg) || stack_slot_is_null_literal (arg))
1391 return TRUE;
1394 switch (stack_slot_get_underlying_type (arg)) {
1395 case TYPE_I4:
1396 case TYPE_I8:
1397 case TYPE_NATIVE_INT:
1398 case TYPE_PTR:
1399 return TRUE;
1400 case TYPE_COMPLEX:
1401 g_assert (arg->type);
1402 switch (arg->type->type) {
1403 case MONO_TYPE_CLASS:
1404 case MONO_TYPE_STRING:
1405 case MONO_TYPE_OBJECT:
1406 case MONO_TYPE_SZARRAY:
1407 case MONO_TYPE_ARRAY:
1408 case MONO_TYPE_FNPTR:
1409 case MONO_TYPE_PTR:
1410 return TRUE;
1411 case MONO_TYPE_GENERICINST:
1412 /*We need to check if the container class
1413 * of the generic type is a valuetype, iow:
1414 * is it a "class Foo<T>" or a "struct Foo<T>"?
1416 return !arg->type->data.generic_class->container_class->valuetype;
1418 default:
1419 return FALSE;
1424 /*Type manipulation helper*/
1426 /*Returns the byref version of the supplied MonoType*/
1427 static MonoType*
1428 mono_type_get_type_byref (MonoType *type)
1430 if (type->byref)
1431 return type;
1432 return &mono_class_from_mono_type (type)->this_arg;
1436 /*Returns the byval version of the supplied MonoType*/
1437 static MonoType*
1438 mono_type_get_type_byval (MonoType *type)
1440 if (!type->byref)
1441 return type;
1442 return &mono_class_from_mono_type (type)->byval_arg;
1445 static MonoType*
1446 mono_type_from_stack_slot (ILStackDesc *slot)
1448 if (stack_slot_is_managed_pointer (slot))
1449 return mono_type_get_type_byref (slot->type);
1450 return slot->type;
1453 /*Stack manipulation code*/
1455 static void
1456 ensure_stack_size (ILCodeDesc *stack, int required)
1458 int new_size = 8;
1459 ILStackDesc *tmp;
1461 if (required < stack->max_size)
1462 return;
1464 /* We don't have to worry about the exponential growth since stack_copy prune unused space */
1465 new_size = MAX (8, MAX (required, stack->max_size * 2));
1467 g_assert (new_size >= stack->size);
1468 g_assert (new_size >= required);
1470 tmp = g_new0 (ILStackDesc, new_size);
1471 MEM_ALLOC (sizeof (ILStackDesc) * new_size);
1473 if (stack->stack) {
1474 if (stack->size)
1475 memcpy (tmp, stack->stack, stack->size * sizeof (ILStackDesc));
1476 g_free (stack->stack);
1477 MEM_FREE (sizeof (ILStackDesc) * stack->max_size);
1480 stack->stack = tmp;
1481 stack->max_size = new_size;
1484 static void
1485 stack_init (VerifyContext *ctx, ILCodeDesc *state)
1487 if (state->flags & IL_CODE_FLAG_STACK_INITED)
1488 return;
1489 state->size = state->max_size = 0;
1490 state->flags |= IL_CODE_FLAG_STACK_INITED;
1493 static void
1494 stack_copy (ILCodeDesc *to, ILCodeDesc *from)
1496 ensure_stack_size (to, from->size);
1497 to->size = from->size;
1499 /*stack copy happens at merge points, which have small stacks*/
1500 if (from->size)
1501 memcpy (to->stack, from->stack, sizeof (ILStackDesc) * from->size);
1504 static void
1505 copy_stack_value (ILStackDesc *to, ILStackDesc *from)
1507 to->stype = from->stype;
1508 to->type = from->type;
1509 to->method = from->method;
1512 static int
1513 check_underflow (VerifyContext *ctx, int size)
1515 if (ctx->eval.size < size) {
1516 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack underflow, required %d, but have %d at 0x%04x", size, ctx->eval.size, ctx->ip_offset));
1517 return 0;
1519 return 1;
1522 static int
1523 check_overflow (VerifyContext *ctx)
1525 if (ctx->eval.size >= ctx->max_stack) {
1526 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have stack-depth %d at 0x%04x", ctx->eval.size + 1, ctx->ip_offset));
1527 return 0;
1529 return 1;
1532 /*This reject out PTR, FNPTR and TYPEDBYREF*/
1533 static gboolean
1534 check_unmanaged_pointer (VerifyContext *ctx, ILStackDesc *value)
1536 if (stack_slot_get_type (value) == TYPE_PTR) {
1537 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1538 return 0;
1540 return 1;
1543 /*TODO verify if MONO_TYPE_TYPEDBYREF is not allowed here as well.*/
1544 static gboolean
1545 check_unverifiable_type (VerifyContext *ctx, MonoType *type)
1547 if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
1548 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1549 return 0;
1551 return 1;
1554 static ILStackDesc *
1555 stack_push (VerifyContext *ctx)
1557 g_assert (ctx->eval.size < ctx->max_stack);
1558 g_assert (ctx->eval.size <= ctx->eval.max_size);
1560 ensure_stack_size (&ctx->eval, ctx->eval.size + 1);
1562 return & ctx->eval.stack [ctx->eval.size++];
1565 static ILStackDesc *
1566 stack_push_val (VerifyContext *ctx, int stype, MonoType *type)
1568 ILStackDesc *top = stack_push (ctx);
1569 top->stype = stype;
1570 top->type = type;
1571 return top;
1574 static ILStackDesc *
1575 stack_pop (VerifyContext *ctx)
1577 ILStackDesc *ret;
1578 g_assert (ctx->eval.size > 0);
1579 ret = ctx->eval.stack + --ctx->eval.size;
1580 if ((ret->stype & UNINIT_THIS_MASK) == UNINIT_THIS_MASK)
1581 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Found use of uninitialized 'this ptr' ref at 0x%04x", ctx->ip_offset));
1582 return ret;
1585 /* This function allows to safely pop an unititialized this ptr from
1586 * the eval stack without marking the method as unverifiable.
1588 static ILStackDesc *
1589 stack_pop_safe (VerifyContext *ctx)
1591 g_assert (ctx->eval.size > 0);
1592 return ctx->eval.stack + --ctx->eval.size;
1595 /*Positive number distance from stack top. [0] is stack top, [1] is the one below*/
1596 static ILStackDesc*
1597 stack_peek (VerifyContext *ctx, int distance)
1599 g_assert (ctx->eval.size - distance > 0);
1600 return ctx->eval.stack + (ctx->eval.size - 1 - distance);
1603 static ILStackDesc *
1604 stack_push_stack_val (VerifyContext *ctx, ILStackDesc *value)
1606 ILStackDesc *top = stack_push (ctx);
1607 copy_stack_value (top, value);
1608 return top;
1611 /* Returns the MonoType associated with the token, or NULL if it is invalid.
1613 * A boxable type can be either a reference or value type, but cannot be a byref type or an unmanaged pointer
1614 * */
1615 static MonoType*
1616 get_boxable_mono_type (VerifyContext* ctx, int token, const char *opcode)
1618 MonoType *type;
1619 MonoClass *class;
1621 if (!(type = verifier_load_type (ctx, token, opcode)))
1622 return NULL;
1624 if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
1625 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type for %s at 0x%04x", opcode, ctx->ip_offset));
1626 return NULL;
1629 if (type->type == MONO_TYPE_VOID) {
1630 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type for %s at 0x%04x", opcode, ctx->ip_offset));
1631 return NULL;
1634 if (type->type == MONO_TYPE_TYPEDBYREF)
1635 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid use of typedbyref for %s at 0x%04x", opcode, ctx->ip_offset));
1637 if (!(class = mono_class_from_mono_type (type)))
1638 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not retrieve type token for %s at 0x%04x", opcode, ctx->ip_offset));
1640 if (class->generic_container && type->type != MONO_TYPE_GENERICINST)
1641 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));
1643 check_unverifiable_type (ctx, type);
1644 return type;
1648 /*operation result tables */
1650 static const unsigned char bin_op_table [TYPE_MAX][TYPE_MAX] = {
1651 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1652 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1653 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1654 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1655 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1656 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1659 static const unsigned char add_table [TYPE_MAX][TYPE_MAX] = {
1660 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1661 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1662 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1663 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1664 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1665 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1668 static const unsigned char sub_table [TYPE_MAX][TYPE_MAX] = {
1669 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1670 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1671 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1672 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1673 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1674 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1677 static const unsigned char int_bin_op_table [TYPE_MAX][TYPE_MAX] = {
1678 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1679 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1680 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1681 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1682 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1683 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1686 static const unsigned char shift_op_table [TYPE_MAX][TYPE_MAX] = {
1687 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1688 {TYPE_I8, TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV},
1689 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1690 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1691 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1692 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1695 static const unsigned char cmp_br_op [TYPE_MAX][TYPE_MAX] = {
1696 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1697 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1698 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1699 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1700 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV},
1701 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1704 static const unsigned char cmp_br_eq_op [TYPE_MAX][TYPE_MAX] = {
1705 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1706 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1707 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV},
1708 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1709 {TYPE_INV, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_I4, TYPE_INV},
1710 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4},
1713 static const unsigned char add_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
1714 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1715 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1716 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1717 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1718 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1719 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1722 static const unsigned char sub_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
1723 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1724 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1725 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1726 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1727 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1728 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1731 static const unsigned char bin_ovf_table [TYPE_MAX][TYPE_MAX] = {
1732 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1733 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1734 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1735 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1736 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1737 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1740 #ifdef MONO_VERIFIER_DEBUG
1742 /*debug helpers */
1743 static void
1744 dump_stack_value (ILStackDesc *value)
1746 printf ("[(%x)(%x)", value->type->type, value->stype);
1748 if (stack_slot_is_this_pointer (value))
1749 printf ("[this] ");
1751 if (stack_slot_is_boxed_value (value))
1752 printf ("[boxed] ");
1754 if (stack_slot_is_null_literal (value))
1755 printf ("[null] ");
1757 if (stack_slot_is_managed_mutability_pointer (value))
1758 printf ("Controled Mutability MP: ");
1760 if (stack_slot_is_managed_pointer (value))
1761 printf ("Managed Pointer to: ");
1763 switch (stack_slot_get_underlying_type (value)) {
1764 case TYPE_INV:
1765 printf ("invalid type]");
1766 return;
1767 case TYPE_I4:
1768 printf ("int32]");
1769 return;
1770 case TYPE_I8:
1771 printf ("int64]");
1772 return;
1773 case TYPE_NATIVE_INT:
1774 printf ("native int]");
1775 return;
1776 case TYPE_R8:
1777 printf ("float64]");
1778 return;
1779 case TYPE_PTR:
1780 printf ("unmanaged pointer]");
1781 return;
1782 case TYPE_COMPLEX:
1783 switch (value->type->type) {
1784 case MONO_TYPE_CLASS:
1785 case MONO_TYPE_VALUETYPE:
1786 printf ("complex] (%s)", value->type->data.klass->name);
1787 return;
1788 case MONO_TYPE_STRING:
1789 printf ("complex] (string)");
1790 return;
1791 case MONO_TYPE_OBJECT:
1792 printf ("complex] (object)");
1793 return;
1794 case MONO_TYPE_SZARRAY:
1795 printf ("complex] (%s [])", value->type->data.klass->name);
1796 return;
1797 case MONO_TYPE_ARRAY:
1798 printf ("complex] (%s [%d %d %d])",
1799 value->type->data.array->eklass->name,
1800 value->type->data.array->rank,
1801 value->type->data.array->numsizes,
1802 value->type->data.array->numlobounds);
1803 return;
1804 case MONO_TYPE_GENERICINST:
1805 printf ("complex] (inst of %s )", value->type->data.generic_class->container_class->name);
1806 return;
1807 case MONO_TYPE_VAR:
1808 printf ("complex] (type generic param !%d - %s) ", value->type->data.generic_param->num, mono_generic_param_info (value->type->data.generic_param)->name);
1809 return;
1810 case MONO_TYPE_MVAR:
1811 printf ("complex] (method generic param !!%d - %s) ", value->type->data.generic_param->num, mono_generic_param_info (value->type->data.generic_param)->name);
1812 return;
1813 default: {
1814 //should be a boxed value
1815 char * name = mono_type_full_name (value->type);
1816 printf ("complex] %s", name);
1817 g_free (name);
1818 return;
1821 default:
1822 printf ("unknown stack %x type]\n", value->stype);
1823 g_assert_not_reached ();
1827 static void
1828 dump_stack_state (ILCodeDesc *state)
1830 int i;
1832 printf ("(%d) ", state->size);
1833 for (i = 0; i < state->size; ++i)
1834 dump_stack_value (state->stack + i);
1835 printf ("\n");
1837 #endif
1839 /*Returns TRUE if candidate array type can be assigned to target.
1840 *Both parameters MUST be of type MONO_TYPE_ARRAY (target->type == MONO_TYPE_ARRAY)
1842 static gboolean
1843 is_array_type_compatible (MonoType *target, MonoType *candidate)
1845 MonoArrayType *left = target->data.array;
1846 MonoArrayType *right = candidate->data.array;
1848 g_assert (target->type == MONO_TYPE_ARRAY);
1849 g_assert (candidate->type == MONO_TYPE_ARRAY);
1851 if (left->rank != right->rank)
1852 return FALSE;
1854 return verifier_class_is_assignable_from (left->eklass, right->eklass);
1857 static int
1858 get_stack_type (MonoType *type)
1860 int mask = 0;
1861 int type_kind = type->type;
1862 if (type->byref)
1863 mask = POINTER_MASK;
1864 /*TODO handle CMMP_MASK */
1866 handle_enum:
1867 switch (type_kind) {
1868 case MONO_TYPE_I1:
1869 case MONO_TYPE_U1:
1870 case MONO_TYPE_BOOLEAN:
1871 case MONO_TYPE_I2:
1872 case MONO_TYPE_U2:
1873 case MONO_TYPE_CHAR:
1874 case MONO_TYPE_I4:
1875 case MONO_TYPE_U4:
1876 return TYPE_I4 | mask;
1878 case MONO_TYPE_I:
1879 case MONO_TYPE_U:
1880 return TYPE_NATIVE_INT | mask;
1882 /* FIXME: the spec says that you cannot have a pointer to method pointer, do we need to check this here? */
1883 case MONO_TYPE_FNPTR:
1884 case MONO_TYPE_PTR:
1885 case MONO_TYPE_TYPEDBYREF:
1886 return TYPE_PTR | mask;
1888 case MONO_TYPE_VAR:
1889 case MONO_TYPE_MVAR:
1891 case MONO_TYPE_CLASS:
1892 case MONO_TYPE_STRING:
1893 case MONO_TYPE_OBJECT:
1894 case MONO_TYPE_SZARRAY:
1895 case MONO_TYPE_ARRAY:
1896 return TYPE_COMPLEX | mask;
1898 case MONO_TYPE_I8:
1899 case MONO_TYPE_U8:
1900 return TYPE_I8 | mask;
1902 case MONO_TYPE_R4:
1903 case MONO_TYPE_R8:
1904 return TYPE_R8 | mask;
1906 case MONO_TYPE_GENERICINST:
1907 case MONO_TYPE_VALUETYPE:
1908 if (mono_type_is_enum_type (type)) {
1909 type = mono_type_get_underlying_type_any (type);
1910 if (!type)
1911 return FALSE;
1912 type_kind = type->type;
1913 goto handle_enum;
1914 } else {
1915 return TYPE_COMPLEX | mask;
1918 default:
1919 return TYPE_INV;
1923 /* convert MonoType to ILStackDesc format (stype) */
1924 static gboolean
1925 set_stack_value (VerifyContext *ctx, ILStackDesc *stack, MonoType *type, int take_addr)
1927 int mask = 0;
1928 int type_kind = type->type;
1930 if (type->byref || take_addr)
1931 mask = POINTER_MASK;
1932 /* TODO handle CMMP_MASK */
1934 handle_enum:
1935 stack->type = type;
1937 switch (type_kind) {
1938 case MONO_TYPE_I1:
1939 case MONO_TYPE_U1:
1940 case MONO_TYPE_BOOLEAN:
1941 case MONO_TYPE_I2:
1942 case MONO_TYPE_U2:
1943 case MONO_TYPE_CHAR:
1944 case MONO_TYPE_I4:
1945 case MONO_TYPE_U4:
1946 stack->stype = TYPE_I4 | mask;
1947 break;
1948 case MONO_TYPE_I:
1949 case MONO_TYPE_U:
1950 stack->stype = TYPE_NATIVE_INT | mask;
1951 break;
1953 /*FIXME: Do we need to check if it's a pointer to the method pointer? The spec says it' illegal to have that.*/
1954 case MONO_TYPE_FNPTR:
1955 case MONO_TYPE_PTR:
1956 case MONO_TYPE_TYPEDBYREF:
1957 stack->stype = TYPE_PTR | mask;
1958 break;
1960 case MONO_TYPE_CLASS:
1961 case MONO_TYPE_STRING:
1962 case MONO_TYPE_OBJECT:
1963 case MONO_TYPE_SZARRAY:
1964 case MONO_TYPE_ARRAY:
1966 case MONO_TYPE_VAR:
1967 case MONO_TYPE_MVAR:
1968 stack->stype = TYPE_COMPLEX | mask;
1969 break;
1971 case MONO_TYPE_I8:
1972 case MONO_TYPE_U8:
1973 stack->stype = TYPE_I8 | mask;
1974 break;
1975 case MONO_TYPE_R4:
1976 case MONO_TYPE_R8:
1977 stack->stype = TYPE_R8 | mask;
1978 break;
1979 case MONO_TYPE_GENERICINST:
1980 case MONO_TYPE_VALUETYPE:
1981 if (mono_type_is_enum_type (type)) {
1982 MonoType *utype = mono_type_get_underlying_type_any (type);
1983 if (!utype) {
1984 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not resolve underlying type of %x at %d", type->type, ctx->ip_offset));
1985 return FALSE;
1987 type = utype;
1988 type_kind = type->type;
1989 goto handle_enum;
1990 } else {
1991 stack->stype = TYPE_COMPLEX | mask;
1992 break;
1994 default:
1995 VERIFIER_DEBUG ( printf ("unknown type 0x%02x in eval stack type\n", type->type); );
1996 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Illegal value set on stack 0x%02x at %d", type->type, ctx->ip_offset));
1997 return FALSE;
1999 return TRUE;
2003 * init_stack_with_value_at_exception_boundary:
2005 * Initialize the stack and push a given type.
2006 * The instruction is marked as been on the exception boundary.
2008 static void
2009 init_stack_with_value_at_exception_boundary (VerifyContext *ctx, ILCodeDesc *code, MonoClass *klass)
2011 MonoError error;
2012 MonoType *type = mono_class_inflate_generic_type_checked (&klass->byval_arg, ctx->generic_context, &error);
2014 if (!mono_error_ok (&error)) {
2015 char *name = mono_type_get_full_name (klass);
2016 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid class %s used for exception", name));
2017 g_free (name);
2018 mono_error_cleanup (&error);
2019 return;
2022 if (!ctx->max_stack) {
2023 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack overflow at 0x%04x", ctx->ip_offset));
2024 return;
2027 stack_init (ctx, code);
2028 ensure_stack_size (code, 1);
2029 set_stack_value (ctx, code->stack, type, FALSE);
2030 ctx->exception_types = g_slist_prepend (ctx->exception_types, type);
2031 code->size = 1;
2032 code->flags |= IL_CODE_FLAG_WAS_TARGET;
2033 if (mono_type_is_generic_argument (type))
2034 code->stack->stype |= BOXED_MASK;
2037 static gboolean
2038 verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate)
2040 static MonoClass* generic_icollection_class = NULL;
2041 static MonoClass* generic_ienumerable_class = NULL;
2042 MonoClass *iface_gtd;
2044 if (mono_class_is_assignable_from (target, candidate))
2045 return TRUE;
2047 if (!MONO_CLASS_IS_INTERFACE (target) || !target->generic_class || candidate->rank != 1)
2048 return FALSE;
2050 if (generic_icollection_class == NULL) {
2051 generic_icollection_class = mono_class_from_name (mono_defaults.corlib,
2052 "System.Collections.Generic", "ICollection`1");
2053 generic_ienumerable_class = mono_class_from_name (mono_defaults.corlib,
2054 "System.Collections.Generic", "IEnumerable`1");
2056 iface_gtd = target->generic_class->container_class;
2057 if (iface_gtd != mono_defaults.generic_ilist_class && iface_gtd != generic_icollection_class && iface_gtd != generic_ienumerable_class)
2058 return FALSE;
2060 target = mono_class_from_mono_type (target->generic_class->context.class_inst->type_argv [0]);
2061 candidate = candidate->element_class;
2062 return mono_class_is_assignable_from (target, candidate);
2065 /*Verify if type 'candidate' can be stored in type 'target'.
2067 * If strict, check for the underlying type and not the verification stack types
2069 static gboolean
2070 verify_type_compatibility_full (VerifyContext *ctx, MonoType *target, MonoType *candidate, gboolean strict)
2072 #define IS_ONE_OF3(T, A, B, C) (T == A || T == B || T == C)
2073 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
2075 MonoType *original_candidate = candidate;
2076 VERIFIER_DEBUG ( printf ("checking type compatibility %s x %s strict %d\n", mono_type_full_name (target), mono_type_full_name (candidate), strict); );
2078 /*only one is byref */
2079 if (candidate->byref ^ target->byref) {
2080 /* converting from native int to byref*/
2081 if (get_stack_type (candidate) == TYPE_NATIVE_INT && target->byref) {
2082 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("using byref native int at 0x%04x", ctx->ip_offset));
2083 return TRUE;
2085 return FALSE;
2087 strict |= target->byref;
2088 /*From now on we don't care about byref anymore, so it's ok to discard it here*/
2089 candidate = mono_type_get_underlying_type_any (candidate);
2091 handle_enum:
2092 switch (target->type) {
2093 case MONO_TYPE_VOID:
2094 return candidate->type == MONO_TYPE_VOID;
2095 case MONO_TYPE_I1:
2096 case MONO_TYPE_U1:
2097 case MONO_TYPE_BOOLEAN:
2098 if (strict)
2099 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I1, MONO_TYPE_U1, MONO_TYPE_BOOLEAN);
2100 case MONO_TYPE_I2:
2101 case MONO_TYPE_U2:
2102 case MONO_TYPE_CHAR:
2103 if (strict)
2104 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I2, MONO_TYPE_U2, MONO_TYPE_CHAR);
2105 case MONO_TYPE_I4:
2106 case MONO_TYPE_U4: {
2107 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2108 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2109 if (strict)
2110 return is_native_int || is_int4;
2111 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2114 case MONO_TYPE_I8:
2115 case MONO_TYPE_U8:
2116 return IS_ONE_OF2 (candidate->type, MONO_TYPE_I8, MONO_TYPE_U8);
2118 case MONO_TYPE_R4:
2119 case MONO_TYPE_R8:
2120 if (strict)
2121 return candidate->type == target->type;
2122 return IS_ONE_OF2 (candidate->type, MONO_TYPE_R4, MONO_TYPE_R8);
2124 case MONO_TYPE_I:
2125 case MONO_TYPE_U: {
2126 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2127 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2128 if (strict)
2129 return is_native_int || is_int4;
2130 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2133 case MONO_TYPE_PTR:
2134 if (candidate->type != MONO_TYPE_PTR)
2135 return FALSE;
2136 /* check the underlying type */
2137 return verify_type_compatibility_full (ctx, target->data.type, candidate->data.type, TRUE);
2139 case MONO_TYPE_FNPTR: {
2140 MonoMethodSignature *left, *right;
2141 if (candidate->type != MONO_TYPE_FNPTR)
2142 return FALSE;
2144 left = mono_type_get_signature (target);
2145 right = mono_type_get_signature (candidate);
2146 return mono_metadata_signature_equal (left, right) && left->call_convention == right->call_convention;
2149 case MONO_TYPE_GENERICINST: {
2150 MonoClass *target_klass;
2151 MonoClass *candidate_klass;
2152 if (mono_type_is_enum_type (target)) {
2153 target = mono_type_get_underlying_type_any (target);
2154 if (!target)
2155 return FALSE;
2156 goto handle_enum;
2159 * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
2160 * to take boxing status into account.
2162 if (mono_type_is_generic_argument (original_candidate))
2163 return FALSE;
2165 target_klass = mono_class_from_mono_type (target);
2166 candidate_klass = mono_class_from_mono_type (candidate);
2167 if (mono_class_is_nullable (target_klass)) {
2168 if (!mono_class_is_nullable (candidate_klass))
2169 return FALSE;
2170 return target_klass == candidate_klass;
2172 return verifier_class_is_assignable_from (target_klass, candidate_klass);
2175 case MONO_TYPE_STRING:
2176 return candidate->type == MONO_TYPE_STRING;
2178 case MONO_TYPE_CLASS:
2180 * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
2181 * to take boxing status into account.
2183 if (mono_type_is_generic_argument (original_candidate))
2184 return FALSE;
2186 if (candidate->type == MONO_TYPE_VALUETYPE)
2187 return FALSE;
2189 /* If candidate is an enum it should return true for System.Enum and supertypes.
2190 * That's why here we use the original type and not the underlying type.
2192 return verifier_class_is_assignable_from (target->data.klass, mono_class_from_mono_type (original_candidate));
2194 case MONO_TYPE_OBJECT:
2195 return MONO_TYPE_IS_REFERENCE (candidate);
2197 case MONO_TYPE_SZARRAY: {
2198 MonoClass *left;
2199 MonoClass *right;
2200 if (candidate->type != MONO_TYPE_SZARRAY)
2201 return FALSE;
2203 left = mono_class_from_mono_type (target);
2204 right = mono_class_from_mono_type (candidate);
2206 return verifier_class_is_assignable_from (left, right);
2209 case MONO_TYPE_ARRAY:
2210 if (candidate->type != MONO_TYPE_ARRAY)
2211 return FALSE;
2212 return is_array_type_compatible (target, candidate);
2214 case MONO_TYPE_TYPEDBYREF:
2215 return candidate->type == MONO_TYPE_TYPEDBYREF;
2217 case MONO_TYPE_VALUETYPE: {
2218 MonoClass *target_klass;
2219 MonoClass *candidate_klass;
2221 if (candidate->type == MONO_TYPE_CLASS)
2222 return FALSE;
2224 target_klass = mono_class_from_mono_type (target);
2225 candidate_klass = mono_class_from_mono_type (candidate);
2226 if (target_klass == candidate_klass)
2227 return TRUE;
2228 if (mono_type_is_enum_type (target)) {
2229 target = mono_type_get_underlying_type_any (target);
2230 if (!target)
2231 return FALSE;
2232 goto handle_enum;
2234 return FALSE;
2237 case MONO_TYPE_VAR:
2238 if (candidate->type != MONO_TYPE_VAR)
2239 return FALSE;
2240 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2242 case MONO_TYPE_MVAR:
2243 if (candidate->type != MONO_TYPE_MVAR)
2244 return FALSE;
2245 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2247 default:
2248 VERIFIER_DEBUG ( printf ("unknown store type %d\n", target->type); );
2249 g_assert_not_reached ();
2250 return FALSE;
2252 return 1;
2253 #undef IS_ONE_OF3
2254 #undef IS_ONE_OF2
2257 static gboolean
2258 verify_type_compatibility (VerifyContext *ctx, MonoType *target, MonoType *candidate)
2260 return verify_type_compatibility_full (ctx, target, candidate, FALSE);
2264 * Returns the generic param bound to the context been verified.
2267 static MonoGenericParam*
2268 get_generic_param (VerifyContext *ctx, MonoType *param)
2270 guint16 param_num = mono_type_get_generic_param_num (param);
2271 if (param->type == MONO_TYPE_VAR) {
2272 if (!ctx->generic_context->class_inst || ctx->generic_context->class_inst->type_argc <= param_num) {
2273 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic type argument %d", param_num));
2274 return NULL;
2276 return ctx->generic_context->class_inst->type_argv [param_num]->data.generic_param;
2279 /*param must be a MVAR */
2280 if (!ctx->generic_context->method_inst || ctx->generic_context->method_inst->type_argc <= param_num) {
2281 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic method argument %d", param_num));
2282 return NULL;
2284 return ctx->generic_context->method_inst->type_argv [param_num]->data.generic_param;
2288 static gboolean
2289 recursive_boxed_constraint_type_check (VerifyContext *ctx, MonoType *type, MonoClass *constraint_class, int recursion_level)
2291 MonoType *constraint_type = &constraint_class->byval_arg;
2292 if (recursion_level <= 0)
2293 return FALSE;
2295 if (verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (constraint_type), FALSE))
2296 return TRUE;
2298 if (mono_type_is_generic_argument (constraint_type)) {
2299 MonoGenericParam *param = get_generic_param (ctx, constraint_type);
2300 MonoClass **class;
2301 if (!param)
2302 return FALSE;
2303 for (class = mono_generic_param_info (param)->constraints; class && *class; ++class) {
2304 if (recursive_boxed_constraint_type_check (ctx, type, *class, recursion_level - 1))
2305 return TRUE;
2308 return FALSE;
2312 * is_compatible_boxed_valuetype:
2314 * Returns TRUE if @candidate / @stack is a valid boxed valuetype.
2316 * @type The source type. It it tested to be of the proper type.
2317 * @candidate type of the boxed valuetype.
2318 * @stack stack slot of the boxed valuetype, separate from @candidade since one could be changed before calling this function
2319 * @strict if TRUE candidate must be boxed compatible to the target type
2322 static gboolean
2323 is_compatible_boxed_valuetype (VerifyContext *ctx, MonoType *type, MonoType *candidate, ILStackDesc *stack, gboolean strict)
2325 if (!stack_slot_is_boxed_value (stack))
2326 return FALSE;
2327 if (type->byref || candidate->byref)
2328 return FALSE;
2330 if (mono_type_is_generic_argument (candidate)) {
2331 MonoGenericParam *param = get_generic_param (ctx, candidate);
2332 MonoClass **class;
2333 if (!param)
2334 return FALSE;
2336 for (class = mono_generic_param_info (param)->constraints; class && *class; ++class) {
2337 /*256 should be enough since there can't be more than 255 generic arguments.*/
2338 if (recursive_boxed_constraint_type_check (ctx, type, *class, 256))
2339 return TRUE;
2343 if (mono_type_is_generic_argument (type))
2344 return FALSE;
2346 if (!strict)
2347 return TRUE;
2349 return MONO_TYPE_IS_REFERENCE (type) && verifier_class_is_assignable_from (mono_class_from_mono_type (type), mono_class_from_mono_type (candidate));
2352 static int
2353 verify_stack_type_compatibility_full (VerifyContext *ctx, MonoType *type, ILStackDesc *stack, gboolean drop_byref, gboolean valuetype_must_be_boxed)
2355 MonoType *candidate = mono_type_from_stack_slot (stack);
2356 if (MONO_TYPE_IS_REFERENCE (type) && !type->byref && stack_slot_is_null_literal (stack))
2357 return TRUE;
2359 if (is_compatible_boxed_valuetype (ctx, type, candidate, stack, TRUE))
2360 return TRUE;
2362 if (valuetype_must_be_boxed && !stack_slot_is_boxed_value (stack) && !MONO_TYPE_IS_REFERENCE (candidate))
2363 return FALSE;
2365 if (!valuetype_must_be_boxed && stack_slot_is_boxed_value (stack))
2366 return FALSE;
2368 if (drop_byref)
2369 return verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (candidate), FALSE);
2371 return verify_type_compatibility_full (ctx, type, candidate, FALSE);
2374 static int
2375 verify_stack_type_compatibility (VerifyContext *ctx, MonoType *type, ILStackDesc *stack)
2377 return verify_stack_type_compatibility_full (ctx, type, stack, FALSE, FALSE);
2380 static gboolean
2381 mono_delegate_type_equal (MonoType *target, MonoType *candidate)
2383 if (candidate->byref ^ target->byref)
2384 return FALSE;
2386 switch (target->type) {
2387 case MONO_TYPE_VOID:
2388 case MONO_TYPE_I1:
2389 case MONO_TYPE_U1:
2390 case MONO_TYPE_BOOLEAN:
2391 case MONO_TYPE_I2:
2392 case MONO_TYPE_U2:
2393 case MONO_TYPE_CHAR:
2394 case MONO_TYPE_I4:
2395 case MONO_TYPE_U4:
2396 case MONO_TYPE_I8:
2397 case MONO_TYPE_U8:
2398 case MONO_TYPE_R4:
2399 case MONO_TYPE_R8:
2400 case MONO_TYPE_I:
2401 case MONO_TYPE_U:
2402 case MONO_TYPE_STRING:
2403 case MONO_TYPE_TYPEDBYREF:
2404 return candidate->type == target->type;
2406 case MONO_TYPE_PTR:
2407 if (candidate->type != MONO_TYPE_PTR)
2408 return FALSE;
2409 return mono_delegate_type_equal (target->data.type, candidate->data.type);
2411 case MONO_TYPE_FNPTR:
2412 if (candidate->type != MONO_TYPE_FNPTR)
2413 return FALSE;
2414 return mono_delegate_signature_equal (mono_type_get_signature (target), mono_type_get_signature (candidate), FALSE);
2416 case MONO_TYPE_GENERICINST: {
2417 MonoClass *target_klass;
2418 MonoClass *candidate_klass;
2419 target_klass = mono_class_from_mono_type (target);
2420 candidate_klass = mono_class_from_mono_type (candidate);
2421 /*FIXME handle nullables and enum*/
2422 return verifier_class_is_assignable_from (target_klass, candidate_klass);
2424 case MONO_TYPE_OBJECT:
2425 return MONO_TYPE_IS_REFERENCE (candidate);
2427 case MONO_TYPE_CLASS:
2428 return verifier_class_is_assignable_from(target->data.klass, mono_class_from_mono_type (candidate));
2430 case MONO_TYPE_SZARRAY:
2431 if (candidate->type != MONO_TYPE_SZARRAY)
2432 return FALSE;
2433 return verifier_class_is_assignable_from (mono_class_from_mono_type (target)->element_class, mono_class_from_mono_type (candidate)->element_class);
2435 case MONO_TYPE_ARRAY:
2436 if (candidate->type != MONO_TYPE_ARRAY)
2437 return FALSE;
2438 return is_array_type_compatible (target, candidate);
2440 case MONO_TYPE_VALUETYPE:
2441 /*FIXME handle nullables and enum*/
2442 return mono_class_from_mono_type (candidate) == mono_class_from_mono_type (target);
2444 case MONO_TYPE_VAR:
2445 return candidate->type == MONO_TYPE_VAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2446 return FALSE;
2448 case MONO_TYPE_MVAR:
2449 return candidate->type == MONO_TYPE_MVAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2450 return FALSE;
2452 default:
2453 VERIFIER_DEBUG ( printf ("Unknown type %d. Implement me!\n", target->type); );
2454 g_assert_not_reached ();
2455 return FALSE;
2459 static gboolean
2460 mono_delegate_param_equal (MonoType *delegate, MonoType *method)
2462 if (mono_metadata_type_equal_full (delegate, method, TRUE))
2463 return TRUE;
2465 return mono_delegate_type_equal (method, delegate);
2468 static gboolean
2469 mono_delegate_ret_equal (MonoType *delegate, MonoType *method)
2471 if (mono_metadata_type_equal_full (delegate, method, TRUE))
2472 return TRUE;
2474 return mono_delegate_type_equal (delegate, method);
2478 * mono_delegate_signature_equal:
2480 * Compare two signatures in the way expected by delegates.
2482 * This function only exists due to the fact that it should ignore the 'has_this' part of the signature.
2484 * FIXME can this function be eliminated and proper metadata functionality be used?
2486 static gboolean
2487 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn)
2489 int i;
2490 int method_offset = is_static_ldftn ? 1 : 0;
2492 if (delegate_sig->param_count + method_offset != method_sig->param_count)
2493 return FALSE;
2495 if (delegate_sig->call_convention != method_sig->call_convention)
2496 return FALSE;
2498 for (i = 0; i < delegate_sig->param_count; i++) {
2499 MonoType *p1 = delegate_sig->params [i];
2500 MonoType *p2 = method_sig->params [i + method_offset];
2502 if (!mono_delegate_param_equal (p1, p2))
2503 return FALSE;
2506 if (!mono_delegate_ret_equal (delegate_sig->ret, method_sig->ret))
2507 return FALSE;
2509 return TRUE;
2512 gboolean
2513 mono_verifier_is_signature_compatible (MonoMethodSignature *target, MonoMethodSignature *candidate)
2515 return mono_delegate_signature_equal (target, candidate, FALSE);
2519 * verify_ldftn_delegate:
2521 * Verify properties of ldftn based delegates.
2523 static void
2524 verify_ldftn_delegate (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2526 MonoMethod *method = funptr->method;
2528 /*ldftn non-final virtuals only allowed if method is not static,
2529 * the object is a this arg (comes from a ldarg.0), and there is no starg.0.
2530 * This rules doesn't apply if the object on stack is a boxed valuetype.
2532 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !(method->klass->flags & TYPE_ATTRIBUTE_SEALED) && !stack_slot_is_boxed_value (value)) {
2533 /*A stdarg 0 must not happen, we fail here only in fail fast mode to avoid double error reports*/
2534 if (IS_FAIL_FAST_MODE (ctx) && ctx->has_this_store)
2535 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at 0x%04x", ctx->ip_offset));
2537 /*current method must not be static*/
2538 if (ctx->method->flags & METHOD_ATTRIBUTE_STATIC)
2539 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function at 0x%04x", ctx->ip_offset));
2541 /*value is the this pointer, loaded using ldarg.0 */
2542 if (!stack_slot_is_this_pointer (value))
2543 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));
2545 ctx->code [ctx->ip_offset].flags |= IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL;
2550 * verify_delegate_compatibility:
2552 * Verify delegate creation sequence.
2555 static void
2556 verify_delegate_compatibility (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2558 #define IS_VALID_OPCODE(offset, opcode) (ip [ip_offset - offset] == opcode && (ctx->code [ip_offset - offset].flags & IL_CODE_FLAG_SEEN))
2559 #define IS_LOAD_FUN_PTR(kind) (IS_VALID_OPCODE (6, CEE_PREFIX1) && ip [ip_offset - 5] == kind)
2561 MonoMethod *invoke, *method;
2562 const guint8 *ip = ctx->header->code;
2563 guint32 ip_offset = ctx->ip_offset;
2564 gboolean is_static_ldftn = FALSE, is_first_arg_bound = FALSE;
2566 if (stack_slot_get_type (funptr) != TYPE_PTR || !funptr->method) {
2567 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid function pointer parameter for delegate constructor at 0x%04x", ctx->ip_offset));
2568 return;
2571 invoke = mono_get_delegate_invoke (delegate);
2572 method = funptr->method;
2574 if (!method || !mono_method_signature (method)) {
2575 char *name = mono_type_get_full_name (delegate);
2576 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid method on stack to create delegate %s construction at 0x%04x", name, ctx->ip_offset));
2577 g_free (name);
2578 return;
2581 if (!invoke || !mono_method_signature (invoke)) {
2582 char *name = mono_type_get_full_name (delegate);
2583 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Delegate type %s with bad Invoke method at 0x%04x", name, ctx->ip_offset));
2584 g_free (name);
2585 return;
2588 is_static_ldftn = (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) && method->flags & METHOD_ATTRIBUTE_STATIC;
2590 if (is_static_ldftn)
2591 is_first_arg_bound = mono_method_signature (invoke)->param_count + 1 == mono_method_signature (method)->param_count;
2593 if (!mono_delegate_signature_equal (mono_method_signature (invoke), mono_method_signature (method), is_first_arg_bound)) {
2594 char *fun_sig = mono_signature_get_desc (mono_method_signature (method), FALSE);
2595 char *invoke_sig = mono_signature_get_desc (mono_method_signature (invoke), FALSE);
2596 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));
2597 g_free (fun_sig);
2598 g_free (invoke_sig);
2602 * Delegate code sequences:
2603 * [-6] ldftn token
2604 * newobj ...
2607 * [-7] dup
2608 * [-6] ldvirtftn token
2609 * newobj ...
2611 * ldftn sequence:*/
2612 if (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) {
2613 verify_ldftn_delegate (ctx, delegate, value, funptr);
2614 } else if (ip_offset > 6 && IS_VALID_OPCODE (7, CEE_DUP) && IS_LOAD_FUN_PTR (CEE_LDVIRTFTN)) {
2615 ctx->code [ip_offset - 6].flags |= IL_CODE_DELEGATE_SEQUENCE;
2616 }else {
2617 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid code sequence for delegate creation at 0x%04x", ctx->ip_offset));
2619 ctx->code [ip_offset].flags |= IL_CODE_DELEGATE_SEQUENCE;
2621 //general tests
2622 if (is_first_arg_bound) {
2623 if (mono_method_signature (method)->param_count == 0 || !verify_stack_type_compatibility_full (ctx, mono_method_signature (method)->params [0], value, FALSE, TRUE))
2624 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2625 } else {
2626 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
2627 if (!stack_slot_is_null_literal (value) && !is_first_arg_bound)
2628 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Non-null this args used with static function for delegate creation at 0x%04x", ctx->ip_offset));
2629 } else {
2630 if (!verify_stack_type_compatibility_full (ctx, &method->klass->byval_arg, value, FALSE, TRUE) && !stack_slot_is_null_literal (value))
2631 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2635 if (stack_slot_get_type (value) != TYPE_COMPLEX)
2636 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid first parameter for delegate creation at 0x%04x", ctx->ip_offset));
2638 #undef IS_VALID_OPCODE
2639 #undef IS_LOAD_FUN_PTR
2642 /* implement the opcode checks*/
2643 static void
2644 push_arg (VerifyContext *ctx, unsigned int arg, int take_addr)
2646 ILStackDesc *top;
2648 if (arg >= ctx->max_args) {
2649 if (take_addr)
2650 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2651 else {
2652 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2653 if (check_overflow (ctx)) //FIXME: what sane value could we ever push?
2654 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
2656 } else if (check_overflow (ctx)) {
2657 /*We must let the value be pushed, otherwise we would get an underflow error*/
2658 check_unverifiable_type (ctx, ctx->params [arg]);
2659 if (ctx->params [arg]->byref && take_addr)
2660 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2661 top = stack_push (ctx);
2662 if (!set_stack_value (ctx, top, ctx->params [arg], take_addr))
2663 return;
2665 if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC)) {
2666 if (take_addr)
2667 ctx->has_this_store = TRUE;
2668 else
2669 top->stype |= THIS_POINTER_MASK;
2670 if (mono_method_is_constructor (ctx->method) && !ctx->super_ctor_called && !ctx->method->klass->valuetype)
2671 top->stype |= UNINIT_THIS_MASK;
2676 static void
2677 push_local (VerifyContext *ctx, guint32 arg, int take_addr)
2679 if (arg >= ctx->num_locals) {
2680 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local %d", arg + 1));
2681 } else if (check_overflow (ctx)) {
2682 /*We must let the value be pushed, otherwise we would get an underflow error*/
2683 check_unverifiable_type (ctx, ctx->locals [arg]);
2684 if (ctx->locals [arg]->byref && take_addr)
2685 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2687 set_stack_value (ctx, stack_push (ctx), ctx->locals [arg], take_addr);
2691 static void
2692 store_arg (VerifyContext *ctx, guint32 arg)
2694 ILStackDesc *value;
2696 if (arg >= ctx->max_args) {
2697 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", arg + 1, ctx->ip_offset));
2698 if (check_underflow (ctx, 1))
2699 stack_pop (ctx);
2700 return;
2703 if (check_underflow (ctx, 1)) {
2704 value = stack_pop (ctx);
2705 if (!verify_stack_type_compatibility (ctx, ctx->params [arg], value)) {
2706 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in argument store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
2709 if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC))
2710 ctx->has_this_store = 1;
2713 static void
2714 store_local (VerifyContext *ctx, guint32 arg)
2716 ILStackDesc *value;
2717 if (arg >= ctx->num_locals) {
2718 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", arg + 1, ctx->ip_offset));
2719 return;
2722 /*TODO verify definite assigment */
2723 if (check_underflow (ctx, 1)) {
2724 value = stack_pop(ctx);
2725 if (!verify_stack_type_compatibility (ctx, ctx->locals [arg], value)) {
2726 char *expected = mono_type_full_name (ctx->locals [arg]);
2727 char *found = stack_slot_full_name (value);
2728 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type '%s' on stack cannot be stored to local %d with type '%s' at 0x%04x",
2729 found,
2730 arg,
2731 expected,
2732 ctx->ip_offset));
2733 g_free (expected);
2734 g_free (found);
2739 /*FIXME add and sub needs special care here*/
2740 static void
2741 do_binop (VerifyContext *ctx, unsigned int opcode, const unsigned char table [TYPE_MAX][TYPE_MAX])
2743 ILStackDesc *a, *b, *top;
2744 int idxa, idxb, complexMerge = 0;
2745 unsigned char res;
2747 if (!check_underflow (ctx, 2))
2748 return;
2749 b = stack_pop (ctx);
2750 a = stack_pop (ctx);
2752 idxa = stack_slot_get_underlying_type (a);
2753 if (stack_slot_is_managed_pointer (a)) {
2754 idxa = TYPE_PTR;
2755 complexMerge = 1;
2758 idxb = stack_slot_get_underlying_type (b);
2759 if (stack_slot_is_managed_pointer (b)) {
2760 idxb = TYPE_PTR;
2761 complexMerge = 2;
2764 --idxa;
2765 --idxb;
2766 res = table [idxa][idxb];
2768 VERIFIER_DEBUG ( printf ("binop res %d\n", res); );
2769 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
2771 top = stack_push (ctx);
2772 if (res == TYPE_INV) {
2773 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)));
2774 copy_stack_value (top, a);
2775 return;
2778 if (res & NON_VERIFIABLE_RESULT) {
2779 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)));
2781 res = res & ~NON_VERIFIABLE_RESULT;
2784 if (complexMerge && res == TYPE_PTR) {
2785 if (complexMerge == 1)
2786 copy_stack_value (top, a);
2787 else if (complexMerge == 2)
2788 copy_stack_value (top, b);
2790 * There is no need to merge the type of two pointers.
2791 * The only valid operation is subtraction, that returns a native
2792 * int as result and can be used with any 2 pointer kinds.
2793 * This is valid acording to Patition III 1.1.4
2795 } else
2796 top->stype = res;
2801 static void
2802 do_boolean_branch_op (VerifyContext *ctx, int delta)
2804 int target = ctx->ip_offset + delta;
2805 ILStackDesc *top;
2807 VERIFIER_DEBUG ( printf ("boolean branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
2809 if (target < 0 || target >= ctx->code_size) {
2810 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Boolean branch target out of code at 0x%04x", ctx->ip_offset));
2811 return;
2814 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
2815 case 1:
2816 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2817 break;
2818 case 2:
2819 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2820 return;
2823 ctx->target = target;
2825 if (!check_underflow (ctx, 1))
2826 return;
2828 top = stack_pop (ctx);
2829 if (!is_valid_bool_arg (top))
2830 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));
2832 check_unmanaged_pointer (ctx, top);
2835 static gboolean
2836 stack_slot_is_complex_type_not_reference_type (ILStackDesc *slot)
2838 return stack_slot_get_type (slot) == TYPE_COMPLEX && !MONO_TYPE_IS_REFERENCE (slot->type) && !stack_slot_is_boxed_value (slot);
2841 static void
2842 do_branch_op (VerifyContext *ctx, signed int delta, const unsigned char table [TYPE_MAX][TYPE_MAX])
2844 ILStackDesc *a, *b;
2845 int idxa, idxb;
2846 unsigned char res;
2847 int target = ctx->ip_offset + delta;
2849 VERIFIER_DEBUG ( printf ("branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
2851 if (target < 0 || target >= ctx->code_size) {
2852 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
2853 return;
2856 switch (is_valid_cmp_branch_instruction (ctx->header, ctx->ip_offset, target)) {
2857 case 1: /*FIXME use constants and not magic numbers.*/
2858 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2859 break;
2860 case 2:
2861 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2862 return;
2865 ctx->target = target;
2867 if (!check_underflow (ctx, 2))
2868 return;
2870 b = stack_pop (ctx);
2871 a = stack_pop (ctx);
2873 idxa = stack_slot_get_underlying_type (a);
2874 if (stack_slot_is_managed_pointer (a))
2875 idxa = TYPE_PTR;
2877 idxb = stack_slot_get_underlying_type (b);
2878 if (stack_slot_is_managed_pointer (b))
2879 idxb = TYPE_PTR;
2881 if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
2882 res = TYPE_INV;
2883 } else {
2884 --idxa;
2885 --idxb;
2886 res = table [idxa][idxb];
2889 VERIFIER_DEBUG ( printf ("branch res %d\n", res); );
2890 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
2892 if (res == TYPE_INV) {
2893 CODE_NOT_VERIFIABLE (ctx,
2894 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));
2895 } else if (res & NON_VERIFIABLE_RESULT) {
2896 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));
2897 res = res & ~NON_VERIFIABLE_RESULT;
2901 static void
2902 do_cmp_op (VerifyContext *ctx, const unsigned char table [TYPE_MAX][TYPE_MAX], guint32 opcode)
2904 ILStackDesc *a, *b;
2905 int idxa, idxb;
2906 unsigned char res;
2908 if (!check_underflow (ctx, 2))
2909 return;
2910 b = stack_pop (ctx);
2911 a = stack_pop (ctx);
2913 if (opcode == CEE_CGT_UN) {
2914 if (stack_slot_get_type (a) == TYPE_COMPLEX && stack_slot_get_type (b) == TYPE_COMPLEX) {
2915 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
2916 return;
2920 idxa = stack_slot_get_underlying_type (a);
2921 if (stack_slot_is_managed_pointer (a))
2922 idxa = TYPE_PTR;
2924 idxb = stack_slot_get_underlying_type (b);
2925 if (stack_slot_is_managed_pointer (b))
2926 idxb = TYPE_PTR;
2928 if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
2929 res = TYPE_INV;
2930 } else {
2931 --idxa;
2932 --idxb;
2933 res = table [idxa][idxb];
2936 if(res == TYPE_INV) {
2937 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));
2938 } else if (res & NON_VERIFIABLE_RESULT) {
2939 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));
2940 res = res & ~NON_VERIFIABLE_RESULT;
2942 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
2945 static void
2946 do_ret (VerifyContext *ctx)
2948 MonoType *ret = ctx->signature->ret;
2949 VERIFIER_DEBUG ( printf ("checking ret\n"); );
2950 if (ret->type != MONO_TYPE_VOID) {
2951 ILStackDesc *top;
2952 if (!check_underflow (ctx, 1))
2953 return;
2955 top = stack_pop(ctx);
2957 if (!verify_stack_type_compatibility (ctx, ctx->signature->ret, top)) {
2958 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible return value on stack with method signature ret at 0x%04x", ctx->ip_offset));
2959 return;
2962 if (ret->byref || ret->type == MONO_TYPE_TYPEDBYREF || mono_type_is_value_type (ret, "System", "ArgIterator") || mono_type_is_value_type (ret, "System", "RuntimeArgumentHandle"))
2963 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method returns byref, TypedReference, ArgIterator or RuntimeArgumentHandle at 0x%04x", ctx->ip_offset));
2966 if (ctx->eval.size > 0) {
2967 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack not empty (%d) after ret at 0x%04x", ctx->eval.size, ctx->ip_offset));
2969 if (in_any_block (ctx->header, ctx->ip_offset))
2970 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ret cannot escape exception blocks at 0x%04x", ctx->ip_offset));
2974 * 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.
2975 * This is illegal but mono_get_method_full decoded it.
2976 * TODO handle calling .ctor outside one or calling the .ctor for other class but super
2978 static void
2979 do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual)
2981 int param_count, i;
2982 MonoMethodSignature *sig;
2983 ILStackDesc *value;
2984 MonoMethod *method;
2985 gboolean virt_check_this = FALSE;
2986 gboolean constrained = ctx->prefix_set & PREFIX_CONSTRAINED;
2988 if (!(method = verifier_load_method (ctx, method_token, virtual ? "callvirt" : "call")))
2989 return;
2991 if (virtual) {
2992 CLEAR_PREFIX (ctx, PREFIX_CONSTRAINED);
2994 if (method->klass->valuetype) // && !constrained ???
2995 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with valuetype method at 0x%04x", ctx->ip_offset));
2997 if ((method->flags & METHOD_ATTRIBUTE_STATIC))
2998 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with static method at 0x%04x", ctx->ip_offset));
3000 } else {
3001 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
3002 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use call with an abstract method at 0x%04x", ctx->ip_offset));
3004 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !(method->klass->flags & TYPE_ATTRIBUTE_SEALED)) {
3005 virt_check_this = TRUE;
3006 ctx->code [ctx->ip_offset].flags |= IL_CODE_CALL_NONFINAL_VIRTUAL;
3010 if (!(sig = mono_method_get_signature_full (method, ctx->image, method_token, ctx->generic_context)))
3011 sig = mono_method_get_signature (method, ctx->image, method_token);
3013 if (!sig) {
3014 char *name = mono_type_get_full_name (method->klass);
3015 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not resolve signature of %s:%s at 0x%04x", name, method->name, ctx->ip_offset));
3016 g_free (name);
3017 return;
3020 param_count = sig->param_count + sig->hasthis;
3021 if (!check_underflow (ctx, param_count))
3022 return;
3024 for (i = sig->param_count - 1; i >= 0; --i) {
3025 VERIFIER_DEBUG ( printf ("verifying argument %d\n", i); );
3026 value = stack_pop (ctx);
3027 if (!verify_stack_type_compatibility (ctx, sig->params[i], value)) {
3028 char *stack_name = stack_slot_full_name (value);
3029 char *sig_name = mono_type_full_name (sig->params [i]);
3030 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));
3031 g_free (stack_name);
3032 g_free (sig_name);
3035 if (stack_slot_is_managed_mutability_pointer (value))
3036 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));
3038 if ((ctx->prefix_set & PREFIX_TAIL) && stack_slot_is_managed_pointer (value)) {
3039 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));
3040 return;
3044 if (sig->hasthis) {
3045 MonoType *type = &method->klass->byval_arg;
3046 ILStackDesc copy;
3048 if (mono_method_is_constructor (method) && !method->klass->valuetype) {
3049 if (!mono_method_is_constructor (ctx->method))
3050 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor outside one at 0x%04x", ctx->ip_offset));
3051 if (method->klass != ctx->method->klass->parent && method->klass != ctx->method->klass)
3052 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor to a type diferent that this or super at 0x%04x", ctx->ip_offset));
3054 ctx->super_ctor_called = TRUE;
3055 value = stack_pop_safe (ctx);
3056 if ((value->stype & THIS_POINTER_MASK) != THIS_POINTER_MASK)
3057 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid 'this ptr' argument for constructor at 0x%04x", ctx->ip_offset));
3058 } else {
3059 value = stack_pop (ctx);
3062 copy_stack_value (&copy, value);
3063 //TODO we should extract this to a 'drop_byref_argument' and use everywhere
3064 //Other parts of the code suffer from the same issue of
3065 copy.type = mono_type_get_type_byval (copy.type);
3066 copy.stype &= ~POINTER_MASK;
3068 if (virt_check_this && !stack_slot_is_this_pointer (value) && !(method->klass->valuetype || stack_slot_is_boxed_value (value)))
3069 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use the call opcode with a non-final virtual method on an object diferent thant the this pointer at 0x%04x", ctx->ip_offset));
3071 if (constrained && virtual) {
3072 if (!stack_slot_is_managed_pointer (value))
3073 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object is not a managed pointer for a constrained call at 0x%04x", ctx->ip_offset));
3074 if (!mono_metadata_type_equal_full (mono_type_get_type_byval (value->type), ctx->constrained_type, TRUE))
3075 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object not compatible with constrained type at 0x%04x", ctx->ip_offset));
3076 copy.stype |= BOXED_MASK;
3077 } else {
3078 if (stack_slot_is_managed_pointer (value) && !mono_class_from_mono_type (value->type)->valuetype)
3079 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));
3081 if (!virtual && mono_class_from_mono_type (value->type)->valuetype && !method->klass->valuetype && !stack_slot_is_boxed_value (value))
3082 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a valuetype baseclass at 0x%04x", ctx->ip_offset));
3084 if (virtual && mono_class_from_mono_type (value->type)->valuetype && !stack_slot_is_boxed_value (value))
3085 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a valuetype with callvirt at 0x%04x", ctx->ip_offset));
3087 if (method->klass->valuetype && (stack_slot_is_boxed_value (value) || !stack_slot_is_managed_pointer (value)))
3088 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));
3090 if (!verify_stack_type_compatibility (ctx, type, &copy)) {
3091 char *expected = mono_type_full_name (type);
3092 char *effective = stack_slot_full_name (&copy);
3093 char *method_name = mono_method_full_name (method, TRUE);
3094 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",
3095 expected, effective, method_name, ctx->ip_offset));
3096 g_free (method_name);
3097 g_free (effective);
3098 g_free (expected);
3101 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, mono_class_from_mono_type (value->type))) {
3102 char *name = mono_method_full_name (method, TRUE);
3103 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3104 g_free (name);
3107 } else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
3108 char *name = mono_method_full_name (method, TRUE);
3109 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3110 g_free (name);
3113 if (sig->ret->type != MONO_TYPE_VOID) {
3114 if (!mono_type_is_valid_in_context (ctx, sig->ret))
3115 return;
3117 if (check_overflow (ctx)) {
3118 value = stack_push (ctx);
3119 set_stack_value (ctx, value, sig->ret, FALSE);
3120 if ((ctx->prefix_set & PREFIX_READONLY) && method->klass->rank && !strcmp (method->name, "Address")) {
3121 ctx->prefix_set &= ~PREFIX_READONLY;
3122 value->stype |= CMMP_MASK;
3127 if ((ctx->prefix_set & PREFIX_TAIL)) {
3128 if (!mono_delegate_ret_equal (mono_method_signature (ctx->method)->ret, sig->ret))
3129 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call with incompatible return type at 0x%04x", ctx->ip_offset));
3130 if (ctx->header->code [ctx->ip_offset + 5] != CEE_RET)
3131 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call not followed by ret at 0x%04x", ctx->ip_offset));
3136 static void
3137 do_push_static_field (VerifyContext *ctx, int token, gboolean take_addr)
3139 MonoClassField *field;
3140 MonoClass *klass;
3141 if (!check_overflow (ctx))
3142 return;
3143 if (!take_addr)
3144 CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3146 if (!(field = verifier_load_field (ctx, token, &klass, take_addr ? "ldsflda" : "ldsfld")))
3147 return;
3149 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3150 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load non static field at 0x%04x", ctx->ip_offset));
3151 return;
3153 /*taking the address of initonly field only works from the static constructor */
3154 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3155 !(field->parent == ctx->method->klass && (ctx->method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_STATIC)) && !strcmp (".cctor", ctx->method->name)))
3156 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
3158 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3159 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3161 set_stack_value (ctx, stack_push (ctx), field->type, take_addr);
3164 static void
3165 do_store_static_field (VerifyContext *ctx, int token) {
3166 MonoClassField *field;
3167 MonoClass *klass;
3168 ILStackDesc *value;
3169 CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3171 if (!check_underflow (ctx, 1))
3172 return;
3174 value = stack_pop (ctx);
3176 if (!(field = verifier_load_field (ctx, token, &klass, "stsfld")))
3177 return;
3179 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3180 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store non static field at 0x%04x", ctx->ip_offset));
3181 return;
3184 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3185 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type in store static field at 0x%04x", ctx->ip_offset));
3186 return;
3189 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3190 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3192 if (!verify_stack_type_compatibility (ctx, field->type, value)) {
3193 char *stack_name = stack_slot_full_name (value);
3194 char *field_name = mono_type_full_name (field->type);
3195 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type in static field store expected '%s' but found '%s' at 0x%04x",
3196 field_name, stack_name, ctx->ip_offset));
3197 g_free (field_name);
3198 g_free (stack_name);
3202 static gboolean
3203 check_is_valid_type_for_field_ops (VerifyContext *ctx, int token, ILStackDesc *obj, MonoClassField **ret_field, const char *opcode)
3205 MonoClassField *field;
3206 MonoClass *klass;
3207 gboolean is_pointer;
3209 /*must be a reference type, a managed pointer, an unamanaged pointer, or a valuetype*/
3210 if (!(field = verifier_load_field (ctx, token, &klass, opcode)))
3211 return FALSE;
3213 *ret_field = field;
3214 //the value on stack is going to be used as a pointer
3215 is_pointer = stack_slot_get_type (obj) == TYPE_PTR || (stack_slot_get_type (obj) == TYPE_NATIVE_INT && !get_stack_type (&field->parent->byval_arg));
3217 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3218 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type at 0x%04x", ctx->ip_offset));
3219 return FALSE;
3221 g_assert (obj->type);
3223 /*The value on the stack must be a subclass of the defining type of the field*/
3224 /* we need to check if we can load the field from the stack value*/
3225 if (is_pointer) {
3226 if (stack_slot_get_underlying_type (obj) == TYPE_NATIVE_INT)
3227 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Native int is not a verifiable type to reference a field at 0x%04x", ctx->ip_offset));
3229 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3230 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3231 } else {
3232 if (!field->parent->valuetype && stack_slot_is_managed_pointer (obj))
3233 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));
3235 /*a value type can be loaded from a value or a managed pointer, but not a boxed object*/
3236 if (field->parent->valuetype && stack_slot_is_boxed_value (obj))
3237 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));
3239 if (!stack_slot_is_null_literal (obj) && !verify_stack_type_compatibility_full (ctx, &field->parent->byval_arg, obj, TRUE, FALSE)) {
3240 char *found = stack_slot_full_name (obj);
3241 char *expected = mono_type_full_name (&field->parent->byval_arg);
3242 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));
3243 g_free (found);
3244 g_free (expected);
3247 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, mono_class_from_mono_type (obj->type)))
3248 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3251 check_unmanaged_pointer (ctx, obj);
3252 return TRUE;
3255 static void
3256 do_push_field (VerifyContext *ctx, int token, gboolean take_addr)
3258 ILStackDesc *obj;
3259 MonoClassField *field;
3261 if (!take_addr)
3262 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3264 if (!check_underflow (ctx, 1))
3265 return;
3266 obj = stack_pop_safe (ctx);
3268 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, take_addr ? "ldflda" : "ldfld"))
3269 return;
3271 if (take_addr && field->parent->valuetype && !stack_slot_is_managed_pointer (obj))
3272 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a temporary value-type at 0x%04x", ctx->ip_offset));
3274 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3275 !(field->parent == ctx->method->klass && mono_method_is_constructor (ctx->method)))
3276 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
3278 set_stack_value (ctx, stack_push (ctx), field->type, take_addr);
3281 static void
3282 do_store_field (VerifyContext *ctx, int token)
3284 ILStackDesc *value, *obj;
3285 MonoClassField *field;
3286 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3288 if (!check_underflow (ctx, 2))
3289 return;
3291 value = stack_pop (ctx);
3292 obj = stack_pop_safe (ctx);
3294 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, "stfld"))
3295 return;
3297 if (!verify_stack_type_compatibility (ctx, field->type, value))
3298 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in field store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3301 /*TODO proper handle for Nullable<T>*/
3302 static void
3303 do_box_value (VerifyContext *ctx, int klass_token)
3305 ILStackDesc *value;
3306 MonoType *type = get_boxable_mono_type (ctx, klass_token, "box");
3307 MonoClass *klass;
3309 if (!type)
3310 return;
3312 if (!check_underflow (ctx, 1))
3313 return;
3315 value = stack_pop (ctx);
3316 /*box is a nop for reference types*/
3318 if (stack_slot_get_underlying_type (value) == TYPE_COMPLEX && MONO_TYPE_IS_REFERENCE (value->type) && MONO_TYPE_IS_REFERENCE (type)) {
3319 stack_push_stack_val (ctx, value)->stype |= BOXED_MASK;
3320 return;
3324 if (!verify_stack_type_compatibility (ctx, type, value))
3325 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for boxing operation at 0x%04x", ctx->ip_offset));
3327 klass = mono_class_from_mono_type (type);
3328 if (mono_class_is_nullable (klass))
3329 type = &mono_class_get_nullable_param (klass)->byval_arg;
3330 stack_push_val (ctx, TYPE_COMPLEX | BOXED_MASK, type);
3333 static void
3334 do_unbox_value (VerifyContext *ctx, int klass_token)
3336 ILStackDesc *value;
3337 MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox");
3339 if (!type)
3340 return;
3342 if (!check_underflow (ctx, 1))
3343 return;
3345 if (!mono_class_from_mono_type (type)->valuetype)
3346 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid reference type for unbox at 0x%04x", ctx->ip_offset));
3348 value = stack_pop (ctx);
3350 /*Value should be: a boxed valuetype or a reference type*/
3351 if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3352 (stack_slot_is_boxed_value (value) || !mono_class_from_mono_type (value->type)->valuetype)))
3353 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));
3355 set_stack_value (ctx, value = stack_push (ctx), mono_type_get_type_byref (type), FALSE);
3356 value->stype |= CMMP_MASK;
3359 static void
3360 do_unbox_any (VerifyContext *ctx, int klass_token)
3362 ILStackDesc *value;
3363 MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox.any");
3365 if (!type)
3366 return;
3368 if (!check_underflow (ctx, 1))
3369 return;
3371 value = stack_pop (ctx);
3373 /*Value should be: a boxed valuetype or a reference type*/
3374 if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3375 (stack_slot_is_boxed_value (value) || !mono_class_from_mono_type (value->type)->valuetype)))
3376 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));
3378 set_stack_value (ctx, stack_push (ctx), type, FALSE);
3381 static void
3382 do_unary_math_op (VerifyContext *ctx, int op)
3384 ILStackDesc *value;
3385 if (!check_underflow (ctx, 1))
3386 return;
3387 value = stack_pop (ctx);
3388 switch (stack_slot_get_type (value)) {
3389 case TYPE_I4:
3390 case TYPE_I8:
3391 case TYPE_NATIVE_INT:
3392 break;
3393 case TYPE_R8:
3394 if (op == CEE_NEG)
3395 break;
3396 case TYPE_COMPLEX: /*only enums are ok*/
3397 if (mono_type_is_enum_type (value->type))
3398 break;
3399 default:
3400 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for unary not at 0x%04x", ctx->ip_offset));
3402 stack_push_stack_val (ctx, value);
3405 static void
3406 do_conversion (VerifyContext *ctx, int kind)
3408 ILStackDesc *value;
3409 if (!check_underflow (ctx, 1))
3410 return;
3411 value = stack_pop (ctx);
3413 switch (stack_slot_get_type (value)) {
3414 case TYPE_I4:
3415 case TYPE_I8:
3416 case TYPE_NATIVE_INT:
3417 case TYPE_R8:
3418 break;
3419 default:
3420 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));
3423 switch (kind) {
3424 case TYPE_I4:
3425 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3426 break;
3427 case TYPE_I8:
3428 stack_push_val (ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
3429 break;
3430 case TYPE_R8:
3431 stack_push_val (ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
3432 break;
3433 case TYPE_NATIVE_INT:
3434 stack_push_val (ctx, TYPE_NATIVE_INT, &mono_defaults.int_class->byval_arg);
3435 break;
3436 default:
3437 g_error ("unknown type %02x in conversion", kind);
3442 static void
3443 do_load_token (VerifyContext *ctx, int token)
3445 gpointer handle;
3446 MonoClass *handle_class;
3447 if (!check_overflow (ctx))
3448 return;
3450 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
3451 handle = mono_method_get_wrapper_data (ctx->method, token);
3452 handle_class = mono_method_get_wrapper_data (ctx->method, token + 1);
3453 if (handle_class == mono_defaults.typehandle_class)
3454 handle = &((MonoClass*)handle)->byval_arg;
3455 } else {
3456 switch (token & 0xff000000) {
3457 case MONO_TOKEN_TYPE_DEF:
3458 case MONO_TOKEN_TYPE_REF:
3459 case MONO_TOKEN_TYPE_SPEC:
3460 case MONO_TOKEN_FIELD_DEF:
3461 case MONO_TOKEN_METHOD_DEF:
3462 case MONO_TOKEN_METHOD_SPEC:
3463 case MONO_TOKEN_MEMBER_REF:
3464 if (!token_bounds_check (ctx->image, token)) {
3465 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));
3466 return;
3468 break;
3469 default:
3470 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));
3471 return;
3474 handle = mono_ldtoken (ctx->image, token, &handle_class, ctx->generic_context);
3477 if (!handle) {
3478 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid token 0x%x for ldtoken at 0x%04x", token, ctx->ip_offset));
3479 return;
3481 if (handle_class == mono_defaults.typehandle_class) {
3482 mono_type_is_valid_in_context (ctx, (MonoType*)handle);
3483 } else if (handle_class == mono_defaults.methodhandle_class) {
3484 mono_method_is_valid_in_context (ctx, (MonoMethod*)handle);
3485 } else if (handle_class == mono_defaults.fieldhandle_class) {
3486 mono_type_is_valid_in_context (ctx, &((MonoClassField*)handle)->parent->byval_arg);
3487 } else {
3488 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid ldtoken type %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
3490 stack_push_val (ctx, TYPE_COMPLEX, mono_class_get_type (handle_class));
3493 static void
3494 do_ldobj_value (VerifyContext *ctx, int token)
3496 ILStackDesc *value;
3497 MonoType *type = get_boxable_mono_type (ctx, token, "ldobj");
3498 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3500 if (!type)
3501 return;
3503 if (!check_underflow (ctx, 1))
3504 return;
3506 value = stack_pop (ctx);
3507 if (!stack_slot_is_managed_pointer (value)
3508 && stack_slot_get_type (value) != TYPE_NATIVE_INT
3509 && !(stack_slot_get_type (value) == TYPE_PTR && value->type->type != MONO_TYPE_FNPTR)) {
3510 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid argument %s to ldobj at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3511 return;
3514 if (stack_slot_get_type (value) == TYPE_NATIVE_INT)
3515 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Using native pointer to ldobj at 0x%04x", ctx->ip_offset));
3517 /*We have a byval on the stack, but the comparison must be strict. */
3518 if (!verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (value->type), TRUE))
3519 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldojb operation at 0x%04x", ctx->ip_offset));
3521 set_stack_value (ctx, stack_push (ctx), type, FALSE);
3524 static void
3525 do_stobj (VerifyContext *ctx, int token)
3527 ILStackDesc *dest, *src;
3528 MonoType *type = get_boxable_mono_type (ctx, token, "stobj");
3529 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3531 if (!type)
3532 return;
3534 if (!check_underflow (ctx, 2))
3535 return;
3537 src = stack_pop (ctx);
3538 dest = stack_pop (ctx);
3540 if (stack_slot_is_managed_mutability_pointer (dest))
3541 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stobj at 0x%04x", ctx->ip_offset));
3543 if (!stack_slot_is_managed_pointer (dest))
3544 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of stobj operation at 0x%04x", ctx->ip_offset));
3546 if (stack_slot_is_boxed_value (src) && !MONO_TYPE_IS_REFERENCE (src->type) && !MONO_TYPE_IS_REFERENCE (type))
3547 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));
3549 if (!verify_stack_type_compatibility (ctx, type, src)) {
3550 char *type_name = mono_type_full_name (type);
3551 char *src_name = stack_slot_full_name (src);
3552 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));
3553 g_free (type_name);
3554 g_free (src_name);
3557 if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3558 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of stobj don't match at 0x%04x", ctx->ip_offset));
3561 static void
3562 do_cpobj (VerifyContext *ctx, int token)
3564 ILStackDesc *dest, *src;
3565 MonoType *type = get_boxable_mono_type (ctx, token, "cpobj");
3566 if (!type)
3567 return;
3569 if (!check_underflow (ctx, 2))
3570 return;
3572 src = stack_pop (ctx);
3573 dest = stack_pop (ctx);
3575 if (!stack_slot_is_managed_pointer (src))
3576 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid source of cpobj operation at 0x%04x", ctx->ip_offset));
3578 if (!stack_slot_is_managed_pointer (dest))
3579 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of cpobj operation at 0x%04x", ctx->ip_offset));
3581 if (stack_slot_is_managed_mutability_pointer (dest))
3582 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with cpobj at 0x%04x", ctx->ip_offset));
3584 if (!verify_type_compatibility (ctx, type, mono_type_get_type_byval (src->type)))
3585 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Token and source types of cpobj don't match at 0x%04x", ctx->ip_offset));
3587 if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3588 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of cpobj don't match at 0x%04x", ctx->ip_offset));
3591 static void
3592 do_initobj (VerifyContext *ctx, int token)
3594 ILStackDesc *obj;
3595 MonoType *stack, *type = get_boxable_mono_type (ctx, token, "initobj");
3596 if (!type)
3597 return;
3599 if (!check_underflow (ctx, 1))
3600 return;
3602 obj = stack_pop (ctx);
3604 if (!stack_slot_is_managed_pointer (obj))
3605 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid object address for initobj at 0x%04x", ctx->ip_offset));
3607 if (stack_slot_is_managed_mutability_pointer (obj))
3608 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with initobj at 0x%04x", ctx->ip_offset));
3610 stack = mono_type_get_type_byval (obj->type);
3611 if (MONO_TYPE_IS_REFERENCE (stack)) {
3612 if (!verify_type_compatibility (ctx, stack, type))
3613 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3614 else if (IS_STRICT_MODE (ctx) && !mono_metadata_type_equal (type, stack))
3615 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3616 } else if (!verify_type_compatibility (ctx, stack, type)) {
3617 char *expected_name = mono_type_full_name (type);
3618 char *stack_name = mono_type_full_name (stack);
3620 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));
3621 g_free (expected_name);
3622 g_free (stack_name);
3626 static void
3627 do_newobj (VerifyContext *ctx, int token)
3629 ILStackDesc *value;
3630 int i;
3631 MonoMethodSignature *sig;
3632 MonoMethod *method;
3633 gboolean is_delegate = FALSE;
3635 if (!(method = verifier_load_method (ctx, token, "newobj")))
3636 return;
3638 if (!mono_method_is_constructor (method)) {
3639 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method from token 0x%08x not a constructor at 0x%04x", token, ctx->ip_offset));
3640 return;
3643 if (method->klass->flags & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE))
3644 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Trying to instantiate an abstract or interface type at 0x%04x", ctx->ip_offset));
3646 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
3647 char *from = mono_method_full_name (ctx->method, TRUE);
3648 char *to = mono_method_full_name (method, TRUE);
3649 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);
3650 g_free (from);
3651 g_free (to);
3654 //FIXME use mono_method_get_signature_full
3655 sig = mono_method_signature (method);
3656 if (!sig) {
3657 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid constructor signature to newobj at 0x%04x", ctx->ip_offset));
3658 return;
3661 if (!sig->hasthis) {
3662 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid constructor signature missing hasthis at 0x%04x", ctx->ip_offset));
3663 return;
3666 if (!check_underflow (ctx, sig->param_count))
3667 return;
3669 is_delegate = method->klass->parent == mono_defaults.multicastdelegate_class;
3671 if (is_delegate) {
3672 ILStackDesc *funptr;
3673 //first arg is object, second arg is fun ptr
3674 if (sig->param_count != 2) {
3675 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid delegate constructor at 0x%04x", ctx->ip_offset));
3676 return;
3678 funptr = stack_pop (ctx);
3679 value = stack_pop (ctx);
3680 verify_delegate_compatibility (ctx, method->klass, value, funptr);
3681 } else {
3682 for (i = sig->param_count - 1; i >= 0; --i) {
3683 VERIFIER_DEBUG ( printf ("verifying constructor argument %d\n", i); );
3684 value = stack_pop (ctx);
3685 if (!verify_stack_type_compatibility (ctx, sig->params [i], value)) {
3686 char *stack_name = stack_slot_full_name (value);
3687 char *sig_name = mono_type_full_name (sig->params [i]);
3688 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));
3689 g_free (stack_name);
3690 g_free (sig_name);
3693 if (stack_slot_is_managed_mutability_pointer (value))
3694 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer as argument of newobj at 0x%04x", ctx->ip_offset));
3698 if (check_overflow (ctx))
3699 set_stack_value (ctx, stack_push (ctx), &method->klass->byval_arg, FALSE);
3702 static void
3703 do_cast (VerifyContext *ctx, int token, const char *opcode) {
3704 ILStackDesc *value;
3705 MonoType *type;
3706 gboolean is_boxed;
3707 gboolean do_box;
3709 if (!check_underflow (ctx, 1))
3710 return;
3712 if (!(type = get_boxable_mono_type (ctx, token, opcode)))
3713 return;
3715 if (type->byref) {
3716 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid %s type at 0x%04x", opcode, ctx->ip_offset));
3717 return;
3720 value = stack_pop (ctx);
3721 is_boxed = stack_slot_is_boxed_value (value);
3723 if (stack_slot_is_managed_pointer (value))
3724 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
3725 else if (!MONO_TYPE_IS_REFERENCE (value->type) && !is_boxed) {
3726 char *name = stack_slot_full_name (value);
3727 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));
3728 g_free (name);
3731 switch (value->type->type) {
3732 case MONO_TYPE_FNPTR:
3733 case MONO_TYPE_PTR:
3734 case MONO_TYPE_TYPEDBYREF:
3735 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
3738 do_box = is_boxed || mono_type_is_generic_argument(type) || mono_class_from_mono_type (type)->valuetype;
3739 stack_push_val (ctx, TYPE_COMPLEX | (do_box ? BOXED_MASK : 0), type);
3742 static MonoType *
3743 mono_type_from_opcode (int opcode) {
3744 switch (opcode) {
3745 case CEE_LDIND_I1:
3746 case CEE_LDIND_U1:
3747 case CEE_STIND_I1:
3748 case CEE_LDELEM_I1:
3749 case CEE_LDELEM_U1:
3750 case CEE_STELEM_I1:
3751 return &mono_defaults.sbyte_class->byval_arg;
3753 case CEE_LDIND_I2:
3754 case CEE_LDIND_U2:
3755 case CEE_STIND_I2:
3756 case CEE_LDELEM_I2:
3757 case CEE_LDELEM_U2:
3758 case CEE_STELEM_I2:
3759 return &mono_defaults.int16_class->byval_arg;
3761 case CEE_LDIND_I4:
3762 case CEE_LDIND_U4:
3763 case CEE_STIND_I4:
3764 case CEE_LDELEM_I4:
3765 case CEE_LDELEM_U4:
3766 case CEE_STELEM_I4:
3767 return &mono_defaults.int32_class->byval_arg;
3769 case CEE_LDIND_I8:
3770 case CEE_STIND_I8:
3771 case CEE_LDELEM_I8:
3772 case CEE_STELEM_I8:
3773 return &mono_defaults.int64_class->byval_arg;
3775 case CEE_LDIND_R4:
3776 case CEE_STIND_R4:
3777 case CEE_LDELEM_R4:
3778 case CEE_STELEM_R4:
3779 return &mono_defaults.single_class->byval_arg;
3781 case CEE_LDIND_R8:
3782 case CEE_STIND_R8:
3783 case CEE_LDELEM_R8:
3784 case CEE_STELEM_R8:
3785 return &mono_defaults.double_class->byval_arg;
3787 case CEE_LDIND_I:
3788 case CEE_STIND_I:
3789 case CEE_LDELEM_I:
3790 case CEE_STELEM_I:
3791 return &mono_defaults.int_class->byval_arg;
3793 case CEE_LDIND_REF:
3794 case CEE_STIND_REF:
3795 case CEE_LDELEM_REF:
3796 case CEE_STELEM_REF:
3797 return &mono_defaults.object_class->byval_arg;
3799 default:
3800 g_error ("unknown opcode %02x in mono_type_from_opcode ", opcode);
3801 return NULL;
3805 static void
3806 do_load_indirect (VerifyContext *ctx, int opcode)
3808 ILStackDesc *value;
3809 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3811 if (!check_underflow (ctx, 1))
3812 return;
3814 value = stack_pop (ctx);
3815 if (!stack_slot_is_managed_pointer (value)) {
3816 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Load indirect not using a manager pointer at 0x%04x", ctx->ip_offset));
3817 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
3818 return;
3821 if (opcode == CEE_LDIND_REF) {
3822 if (stack_slot_get_underlying_type (value) != TYPE_COMPLEX || mono_class_from_mono_type (value->type)->valuetype)
3823 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind_ref expected object byref operation at 0x%04x", ctx->ip_offset));
3824 set_stack_value (ctx, stack_push (ctx), mono_type_get_type_byval (value->type), FALSE);
3825 } else {
3826 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (value->type), TRUE))
3827 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
3828 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
3832 static void
3833 do_store_indirect (VerifyContext *ctx, int opcode)
3835 ILStackDesc *addr, *val;
3836 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3838 if (!check_underflow (ctx, 2))
3839 return;
3841 val = stack_pop (ctx);
3842 addr = stack_pop (ctx);
3844 check_unmanaged_pointer (ctx, addr);
3846 if (!stack_slot_is_managed_pointer (addr) && stack_slot_get_type (addr) != TYPE_PTR) {
3847 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid non-pointer argument to stind at 0x%04x", ctx->ip_offset));
3848 return;
3851 if (stack_slot_is_managed_mutability_pointer (addr)) {
3852 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stind at 0x%04x", ctx->ip_offset));
3853 return;
3856 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (addr->type), TRUE))
3857 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid addr type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
3859 if (!verify_stack_type_compatibility (ctx, mono_type_from_opcode (opcode), val))
3860 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
3863 static void
3864 do_newarr (VerifyContext *ctx, int token)
3866 ILStackDesc *value;
3867 MonoType *type = get_boxable_mono_type (ctx, token, "newarr");
3869 if (!type)
3870 return;
3872 if (!check_underflow (ctx, 1))
3873 return;
3875 value = stack_pop (ctx);
3876 if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
3877 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));
3879 set_stack_value (ctx, stack_push (ctx), mono_class_get_type (mono_array_class_get (mono_class_from_mono_type (type), 1)), FALSE);
3882 /*FIXME handle arrays that are not 0-indexed*/
3883 static void
3884 do_ldlen (VerifyContext *ctx)
3886 ILStackDesc *value;
3888 if (!check_underflow (ctx, 1))
3889 return;
3891 value = stack_pop (ctx);
3893 if (stack_slot_get_type (value) != TYPE_COMPLEX || value->type->type != MONO_TYPE_SZARRAY)
3894 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type for ldlen at 0x%04x", ctx->ip_offset));
3896 stack_push_val (ctx, TYPE_NATIVE_INT, &mono_defaults.int_class->byval_arg);
3899 /*FIXME handle arrays that are not 0-indexed*/
3900 /*FIXME handle readonly prefix and CMMP*/
3901 static void
3902 do_ldelema (VerifyContext *ctx, int klass_token)
3904 ILStackDesc *index, *array, *res;
3905 MonoType *type = get_boxable_mono_type (ctx, klass_token, "ldelema");
3906 gboolean valid;
3908 if (!type)
3909 return;
3911 if (!check_underflow (ctx, 2))
3912 return;
3914 index = stack_pop (ctx);
3915 array = stack_pop (ctx);
3917 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
3918 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));
3920 if (!stack_slot_is_null_literal (array)) {
3921 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
3922 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type(%s) for ldelema at 0x%04x", stack_slot_get_name (array), ctx->ip_offset));
3923 else {
3924 if (get_stack_type (type) == TYPE_I4 || get_stack_type (type) == TYPE_NATIVE_INT) {
3925 valid = verify_type_compatibility_full (ctx, type, &array->type->data.klass->byval_arg, TRUE);
3926 } else {
3927 valid = mono_metadata_type_equal (type, &array->type->data.klass->byval_arg);
3929 if (!valid)
3930 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelema at 0x%04x", ctx->ip_offset));
3934 res = stack_push (ctx);
3935 set_stack_value (ctx, res, type, TRUE);
3936 if (ctx->prefix_set & PREFIX_READONLY) {
3937 ctx->prefix_set &= ~PREFIX_READONLY;
3938 res->stype |= CMMP_MASK;
3943 * FIXME handle arrays that are not 0-indexed
3944 * FIXME handle readonly prefix and CMMP
3946 static void
3947 do_ldelem (VerifyContext *ctx, int opcode, int token)
3949 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
3950 ILStackDesc *index, *array;
3951 MonoType *type;
3952 if (!check_underflow (ctx, 2))
3953 return;
3955 if (opcode == CEE_LDELEM) {
3956 if (!(type = verifier_load_type (ctx, token, "ldelem.any"))) {
3957 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
3958 return;
3960 } else {
3961 type = mono_type_from_opcode (opcode);
3964 index = stack_pop (ctx);
3965 array = stack_pop (ctx);
3967 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
3968 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));
3970 if (!stack_slot_is_null_literal (array)) {
3971 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
3972 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));
3973 else {
3974 if (opcode == CEE_LDELEM_REF) {
3975 if (array->type->data.klass->valuetype)
3976 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for ldelem.ref 0x%04x", ctx->ip_offset));
3977 type = &array->type->data.klass->byval_arg;
3978 } else {
3979 MonoType *candidate = &array->type->data.klass->byval_arg;
3980 if (IS_STRICT_MODE (ctx)) {
3981 MonoType *underlying_type = mono_type_get_underlying_type_any (type);
3982 MonoType *underlying_candidate = mono_type_get_underlying_type_any (candidate);
3983 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)) ||
3984 (IS_ONE_OF2 (underlying_candidate->type, MONO_TYPE_I4, MONO_TYPE_U4) && IS_ONE_OF2 (underlying_type->type, MONO_TYPE_I, MONO_TYPE_U)))
3985 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
3987 if (!verify_type_compatibility_full (ctx, type, candidate, TRUE))
3988 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
3993 set_stack_value (ctx, stack_push (ctx), type, FALSE);
3994 #undef IS_ONE_OF2
3998 * FIXME handle arrays that are not 0-indexed
4000 static void
4001 do_stelem (VerifyContext *ctx, int opcode, int token)
4003 ILStackDesc *index, *array, *value;
4004 MonoType *type;
4005 if (!check_underflow (ctx, 3))
4006 return;
4008 if (opcode == CEE_STELEM) {
4009 if (!(type = verifier_load_type (ctx, token, "stelem.any"))) {
4010 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
4011 return;
4013 } else {
4014 type = mono_type_from_opcode (opcode);
4017 value = stack_pop (ctx);
4018 index = stack_pop (ctx);
4019 array = stack_pop (ctx);
4021 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4022 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));
4024 if (!stack_slot_is_null_literal (array)) {
4025 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY) {
4026 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));
4027 } else {
4028 if (opcode == CEE_STELEM_REF) {
4029 if (array->type->data.klass->valuetype)
4030 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4031 } else if (!verify_type_compatibility_full (ctx, &array->type->data.klass->byval_arg, type, TRUE)) {
4032 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4036 if (opcode == CEE_STELEM_REF) {
4037 if (!stack_slot_is_boxed_value (value) && mono_class_from_mono_type (value->type)->valuetype)
4038 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4039 } else if (opcode != CEE_STELEM_REF) {
4040 if (!verify_stack_type_compatibility (ctx, type, value))
4041 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4043 if (stack_slot_is_boxed_value (value) && !MONO_TYPE_IS_REFERENCE (value->type) && !MONO_TYPE_IS_REFERENCE (type))
4044 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));
4049 static void
4050 do_throw (VerifyContext *ctx)
4052 ILStackDesc *exception;
4053 if (!check_underflow (ctx, 1))
4054 return;
4055 exception = stack_pop (ctx);
4057 if (!stack_slot_is_null_literal (exception) && !(stack_slot_get_type (exception) == TYPE_COMPLEX && !mono_class_from_mono_type (exception->type)->valuetype))
4058 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type on stack for throw, expected reference type at 0x%04x", ctx->ip_offset));
4060 if (mono_type_is_generic_argument (exception->type) && !stack_slot_is_boxed_value (exception)) {
4061 char *name = mono_type_full_name (exception->type);
4062 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));
4063 g_free (name);
4065 /*The stack is left empty after a throw*/
4066 ctx->eval.size = 0;
4070 static void
4071 do_endfilter (VerifyContext *ctx)
4073 MonoExceptionClause *clause;
4075 if (IS_STRICT_MODE (ctx)) {
4076 if (ctx->eval.size != 1)
4077 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack size must have one item for endfilter at 0x%04x", ctx->ip_offset));
4079 if (ctx->eval.size >= 1 && stack_slot_get_type (stack_pop (ctx)) != TYPE_I4)
4080 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack item type is not an int32 for endfilter at 0x%04x", ctx->ip_offset));
4083 if ((clause = is_correct_endfilter (ctx, ctx->ip_offset))) {
4084 if (IS_STRICT_MODE (ctx)) {
4085 if (ctx->ip_offset != clause->handler_offset - 2)
4086 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
4087 } else {
4088 if ((ctx->ip_offset != clause->handler_offset - 2) && !MONO_OFFSET_IN_HANDLER (clause, ctx->ip_offset))
4089 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
4091 } else {
4092 if (IS_STRICT_MODE (ctx) && !is_unverifiable_endfilter (ctx, ctx->ip_offset))
4093 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4094 else
4095 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4098 ctx->eval.size = 0;
4101 static void
4102 do_leave (VerifyContext *ctx, int delta)
4104 int target = ((gint32)ctx->ip_offset) + delta;
4105 if (target >= ctx->code_size || target < 0)
4106 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
4108 if (!is_correct_leave (ctx->header, ctx->ip_offset, target))
4109 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ctx->ip_offset));
4110 ctx->eval.size = 0;
4111 ctx->target = target;
4115 * do_static_branch:
4117 * Verify br and br.s opcodes.
4119 static void
4120 do_static_branch (VerifyContext *ctx, int delta)
4122 int target = ctx->ip_offset + delta;
4123 if (target < 0 || target >= ctx->code_size) {
4124 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("branch target out of code at 0x%04x", ctx->ip_offset));
4125 return;
4128 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4129 case 1:
4130 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4131 break;
4132 case 2:
4133 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4134 break;
4137 ctx->target = target;
4140 static void
4141 do_switch (VerifyContext *ctx, int count, const unsigned char *data)
4143 int i, base = ctx->ip_offset + 5 + count * 4;
4144 ILStackDesc *value;
4146 if (!check_underflow (ctx, 1))
4147 return;
4149 value = stack_pop (ctx);
4151 if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
4152 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to switch at 0x%04x", ctx->ip_offset));
4154 for (i = 0; i < count; ++i) {
4155 int target = base + read32 (data + i * 4);
4157 if (target < 0 || target >= ctx->code_size) {
4158 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x out of code at 0x%04x", i, ctx->ip_offset));
4159 return;
4162 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4163 case 1:
4164 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4165 break;
4166 case 2:
4167 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4168 return;
4170 merge_stacks (ctx, &ctx->eval, &ctx->code [target], FALSE, TRUE);
4174 static void
4175 do_load_function_ptr (VerifyContext *ctx, guint32 token, gboolean virtual)
4177 ILStackDesc *top;
4178 MonoMethod *method;
4180 if (virtual && !check_underflow (ctx, 1))
4181 return;
4183 if (!virtual && !check_overflow (ctx))
4184 return;
4186 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
4187 method = mono_method_get_wrapper_data (ctx->method, (guint32)token);
4188 if (!method) {
4189 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4190 return;
4192 } else {
4193 if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
4194 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4195 return;
4198 if (!(method = verifier_load_method (ctx, token, virtual ? "ldvirtfrn" : "ldftn")))
4199 return;
4202 if (mono_method_is_constructor (method))
4203 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldftn with a constructor at 0x%04x", ctx->ip_offset));
4205 if (virtual) {
4206 ILStackDesc *top = stack_pop (ctx);
4208 if (stack_slot_get_type (top) != TYPE_COMPLEX || top->type->type == MONO_TYPE_VALUETYPE)
4209 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to ldvirtftn at 0x%04x", ctx->ip_offset));
4211 if (method->flags & METHOD_ATTRIBUTE_STATIC)
4212 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldvirtftn with a constructor at 0x%04x", ctx->ip_offset));
4214 if (!verify_stack_type_compatibility (ctx, &method->klass->byval_arg, top))
4215 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unexpected object for ldvirtftn at 0x%04x", ctx->ip_offset));
4218 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL))
4219 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);
4221 top = stack_push_val(ctx, TYPE_PTR, mono_type_create_fnptr_from_mono_method (ctx, method));
4222 top->method = method;
4225 static void
4226 do_sizeof (VerifyContext *ctx, int token)
4228 MonoType *type;
4230 if (!(type = verifier_load_type (ctx, token, "sizeof")))
4231 return;
4233 if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
4234 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type at 0x%04x", ctx->ip_offset));
4235 return;
4238 if (type->type == MONO_TYPE_VOID) {
4239 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type at 0x%04x", ctx->ip_offset));
4240 return;
4243 if (check_overflow (ctx))
4244 set_stack_value (ctx, stack_push (ctx), &mono_defaults.uint32_class->byval_arg, FALSE);
4247 /* Stack top can be of any type, the runtime doesn't care and treat everything as an int. */
4248 static void
4249 do_localloc (VerifyContext *ctx)
4251 ILStackDesc *top;
4253 if (ctx->eval.size != 1) {
4254 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4255 return;
4258 if (in_any_exception_block (ctx->header, ctx->ip_offset)) {
4259 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4260 return;
4263 /*TODO verify top type*/
4264 top = stack_pop (ctx);
4266 set_stack_value (ctx, stack_push (ctx), &mono_defaults.int_class->byval_arg, FALSE);
4267 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Instruction localloc in never verifiable at 0x%04x", ctx->ip_offset));
4270 static void
4271 do_ldstr (VerifyContext *ctx, guint32 token)
4273 GSList *error = NULL;
4274 if (ctx->method->wrapper_type == MONO_WRAPPER_NONE && !ctx->image->dynamic) {
4275 if (mono_metadata_token_code (token) != MONO_TOKEN_STRING) {
4276 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string token %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4277 return;
4280 if (!mono_verifier_verify_string_signature (ctx->image, mono_metadata_token_index (token), &error)) {
4281 if (error)
4282 ctx->list = g_slist_concat (ctx->list, error);
4283 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string index %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4284 return;
4288 if (check_overflow (ctx))
4289 stack_push_val (ctx, TYPE_COMPLEX, &mono_defaults.string_class->byval_arg);
4292 static void
4293 do_refanyval (VerifyContext *ctx, int token)
4295 ILStackDesc *top;
4296 MonoType *type;
4297 if (!check_underflow (ctx, 1))
4298 return;
4300 if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4301 return;
4303 top = stack_pop (ctx);
4305 if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4306 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));
4308 set_stack_value (ctx, stack_push (ctx), type, TRUE);
4311 static void
4312 do_refanytype (VerifyContext *ctx)
4314 ILStackDesc *top;
4316 if (!check_underflow (ctx, 1))
4317 return;
4319 top = stack_pop (ctx);
4321 if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4322 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));
4324 set_stack_value (ctx, stack_push (ctx), &mono_defaults.typehandle_class->byval_arg, FALSE);
4328 static void
4329 do_mkrefany (VerifyContext *ctx, int token)
4331 ILStackDesc *top;
4332 MonoType *type;
4333 if (!check_underflow (ctx, 1))
4334 return;
4336 if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4337 return;
4339 top = stack_pop (ctx);
4341 if (stack_slot_is_managed_mutability_pointer (top))
4342 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with mkrefany at 0x%04x", ctx->ip_offset));
4344 if (!stack_slot_is_managed_pointer (top)) {
4345 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));
4346 }else {
4347 MonoType *stack_type = mono_type_get_type_byval (top->type);
4348 if (MONO_TYPE_IS_REFERENCE (type) && !mono_metadata_type_equal (type, stack_type))
4349 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4351 if (!MONO_TYPE_IS_REFERENCE (type) && !verify_type_compatibility_full (ctx, type, stack_type, TRUE))
4352 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4355 set_stack_value (ctx, stack_push (ctx), &mono_defaults.typed_reference_class->byval_arg, FALSE);
4358 static void
4359 do_ckfinite (VerifyContext *ctx)
4361 ILStackDesc *top;
4362 if (!check_underflow (ctx, 1))
4363 return;
4365 top = stack_pop (ctx);
4367 if (stack_slot_get_underlying_type (top) != TYPE_R8)
4368 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));
4369 stack_push_stack_val (ctx, top);
4372 * merge_stacks:
4373 * Merge the stacks and perform compat checks. The merge check if types of @from are mergeable with type of @to
4375 * @from holds new values for a given control path
4376 * @to holds the current values of a given control path
4378 * TODO we can eliminate the from argument as all callers pass &ctx->eval
4380 static void
4381 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external)
4383 MonoError error;
4384 int i, j, k;
4385 stack_init (ctx, to);
4387 if (start) {
4388 if (to->flags == IL_CODE_FLAG_NOT_PROCESSED)
4389 from->size = 0;
4390 else
4391 stack_copy (&ctx->eval, to);
4392 goto end_verify;
4393 } else if (!(to->flags & IL_CODE_STACK_MERGED)) {
4394 stack_copy (to, &ctx->eval);
4395 goto end_verify;
4397 VERIFIER_DEBUG ( printf ("performing stack merge %d x %d\n", from->size, to->size); );
4399 if (from->size != to->size) {
4400 VERIFIER_DEBUG ( printf ("different stack sizes %d x %d at 0x%04x\n", from->size, to->size, ctx->ip_offset); );
4401 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));
4402 goto end_verify;
4405 //FIXME we need to preserve CMMP attributes
4406 //FIXME we must take null literals into consideration.
4407 for (i = 0; i < from->size; ++i) {
4408 ILStackDesc *new_slot = from->stack + i;
4409 ILStackDesc *old_slot = to->stack + i;
4410 MonoType *new_type = mono_type_from_stack_slot (new_slot);
4411 MonoType *old_type = mono_type_from_stack_slot (old_slot);
4412 MonoClass *old_class = mono_class_from_mono_type (old_type);
4413 MonoClass *new_class = mono_class_from_mono_type (new_type);
4414 MonoClass *match_class = NULL;
4416 // S := T then U = S (new value is compatible with current value, keep current)
4417 if (verify_stack_type_compatibility (ctx, old_type, new_slot)) {
4418 copy_stack_value (new_slot, old_slot);
4419 continue;
4422 // T := S then U = T (old value is compatible with current value, use new)
4423 if (verify_stack_type_compatibility (ctx, new_type, old_slot)) {
4424 copy_stack_value (old_slot, new_slot);
4425 continue;
4428 if (mono_type_is_generic_argument (old_type) || mono_type_is_generic_argument (new_type)) {
4429 char *old_name = stack_slot_full_name (old_slot);
4430 char *new_name = stack_slot_full_name (new_slot);
4431 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));
4432 g_free (old_name);
4433 g_free (new_name);
4434 goto end_verify;
4437 //both are reference types, use closest common super type
4438 if (!mono_class_from_mono_type (old_type)->valuetype
4439 && !mono_class_from_mono_type (new_type)->valuetype
4440 && !stack_slot_is_managed_pointer (old_slot)
4441 && !stack_slot_is_managed_pointer (new_slot)) {
4443 mono_class_setup_supertypes (old_class);
4444 mono_class_setup_supertypes (new_class);
4446 for (j = MIN (old_class->idepth, new_class->idepth) - 1; j > 0; --j) {
4447 if (mono_metadata_type_equal (&old_class->supertypes [j]->byval_arg, &new_class->supertypes [j]->byval_arg)) {
4448 match_class = old_class->supertypes [j];
4449 goto match_found;
4453 mono_class_setup_interfaces (old_class, &error);
4454 if (!mono_error_ok (&error)) {
4455 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));
4456 mono_error_cleanup (&error);
4457 goto end_verify;
4459 for (j = 0; j < old_class->interface_count; ++j) {
4460 for (k = 0; k < new_class->interface_count; ++k) {
4461 if (mono_metadata_type_equal (&old_class->interfaces [j]->byval_arg, &new_class->interfaces [k]->byval_arg)) {
4462 match_class = old_class->interfaces [j];
4463 goto match_found;
4468 //No decent super type found, use object
4469 match_class = mono_defaults.object_class;
4470 goto match_found;
4471 } 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)) {
4472 match_class = mono_defaults.object_class;
4473 goto match_found;
4477 char *old_name = stack_slot_full_name (old_slot);
4478 char *new_name = stack_slot_full_name (new_slot);
4479 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));
4480 g_free (old_name);
4481 g_free (new_name);
4483 set_stack_value (ctx, old_slot, &new_class->byval_arg, stack_slot_is_managed_pointer (old_slot));
4484 goto end_verify;
4486 match_found:
4487 g_assert (match_class);
4488 set_stack_value (ctx, old_slot, &match_class->byval_arg, stack_slot_is_managed_pointer (old_slot));
4489 set_stack_value (ctx, new_slot, &match_class->byval_arg, stack_slot_is_managed_pointer (old_slot));
4490 continue;
4493 end_verify:
4494 if (external)
4495 to->flags |= IL_CODE_FLAG_WAS_TARGET;
4496 to->flags |= IL_CODE_STACK_MERGED;
4499 #define HANDLER_START(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER ? (clause)->data.filter_offset : clause->handler_offset)
4500 #define IS_CATCH_OR_FILTER(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER || (clause)->flags == MONO_EXCEPTION_CLAUSE_NONE)
4503 * is_clause_in_range :
4505 * Returns TRUE if either the protected block or the handler of @clause is in the @start - @end range.
4507 static gboolean
4508 is_clause_in_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4510 if (clause->try_offset >= start && clause->try_offset < end)
4511 return TRUE;
4512 if (HANDLER_START (clause) >= start && HANDLER_START (clause) < end)
4513 return TRUE;
4514 return FALSE;
4518 * is_clause_inside_range :
4520 * Returns TRUE if @clause lies completely inside the @start - @end range.
4522 static gboolean
4523 is_clause_inside_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4525 if (clause->try_offset < start || (clause->try_offset + clause->try_len) > end)
4526 return FALSE;
4527 if (HANDLER_START (clause) < start || (clause->handler_offset + clause->handler_len) > end)
4528 return FALSE;
4529 return TRUE;
4533 * is_clause_nested :
4535 * Returns TRUE if @nested is nested in @clause.
4537 static gboolean
4538 is_clause_nested (MonoExceptionClause *clause, MonoExceptionClause *nested)
4540 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (nested, clause->data.filter_offset, clause->handler_offset))
4541 return TRUE;
4542 return is_clause_inside_range (nested, clause->try_offset, clause->try_offset + clause->try_len) ||
4543 is_clause_inside_range (nested, clause->handler_offset, clause->handler_offset + clause->handler_len);
4546 /* Test the relationship between 2 exception clauses. Follow P.1 12.4.2.7 of ECMA
4547 * the each pair of exception must have the following properties:
4548 * - one is fully nested on another (the outer must not be a filter clause) (the nested one must come earlier)
4549 * - completely disjoin (none of the 3 regions of each entry overlap with the other 3)
4550 * - mutual protection (protected block is EXACT the same, handlers are disjoin and all handler are catch or all handler are filter)
4552 static void
4553 verify_clause_relationship (VerifyContext *ctx, MonoExceptionClause *clause, MonoExceptionClause *to_test)
4555 /*clause is nested*/
4556 if (to_test->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (clause, to_test->data.filter_offset, to_test->handler_offset)) {
4557 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clause inside filter"));
4558 return;
4561 /*wrong nesting order.*/
4562 if (is_clause_nested (clause, to_test)) {
4563 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Nested exception clause appears after enclosing clause"));
4564 return;
4567 /*mutual protection*/
4568 if (clause->try_offset == to_test->try_offset && clause->try_len == to_test->try_len) {
4569 /*handlers are not disjoint*/
4570 if (is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) {
4571 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception handlers overlap"));
4572 return;
4574 /* handlers are not catch or filter */
4575 if (!IS_CATCH_OR_FILTER (clause) || !IS_CATCH_OR_FILTER (to_test)) {
4576 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses with shared protected block are neither catch or filter"));
4577 return;
4579 /*OK*/
4580 return;
4583 /*not completelly disjoint*/
4584 if ((is_clause_in_range (to_test, clause->try_offset, clause->try_offset + clause->try_len) ||
4585 is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) && !is_clause_nested (to_test, clause))
4586 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses overlap"));
4589 #define code_bounds_check(size) \
4590 if (ADDP_IS_GREATER_OR_OVF (ip, size, end)) {\
4591 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Code overrun starting with 0x%x at 0x%04x", *ip, ctx.ip_offset)); \
4592 break; \
4595 static gboolean
4596 mono_opcode_is_prefix (int op)
4598 switch (op) {
4599 case MONO_CEE_UNALIGNED_:
4600 case MONO_CEE_VOLATILE_:
4601 case MONO_CEE_TAIL_:
4602 case MONO_CEE_CONSTRAINED_:
4603 case MONO_CEE_READONLY_:
4604 return TRUE;
4606 return FALSE;
4610 * FIXME: need to distinguish between valid and verifiable.
4611 * Need to keep track of types on the stack.
4612 * Verify types for opcodes.
4614 GSList*
4615 mono_method_verify (MonoMethod *method, int level)
4617 MonoError error;
4618 const unsigned char *ip, *code_start;
4619 const unsigned char *end;
4620 MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
4622 int i, n, need_merge = 0, start = 0;
4623 guint token, ip_offset = 0, prefix = 0;
4624 MonoGenericContext *generic_context = NULL;
4625 MonoImage *image;
4626 VerifyContext ctx;
4627 GSList *tmp;
4628 VERIFIER_DEBUG ( printf ("Verify IL for method %s %s %s\n", method->klass->name_space, method->klass->name, method->name); );
4630 init_verifier_stats ();
4632 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
4633 (method->flags & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT))) {
4634 return NULL;
4637 memset (&ctx, 0, sizeof (VerifyContext));
4639 //FIXME use mono_method_get_signature_full
4640 ctx.signature = mono_method_signature (method);
4641 if (!ctx.signature) {
4642 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method signature"));
4644 finish_collect_stats ();
4645 return ctx.list;
4647 if (!method->is_generic && !method->klass->is_generic && ctx.signature->has_type_parameters) {
4648 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Method and signature don't match in terms of genericity"));
4649 finish_collect_stats ();
4650 return ctx.list;
4653 ctx.header = mono_method_get_header (method);
4654 if (!ctx.header) {
4655 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method header"));
4656 finish_collect_stats ();
4657 return ctx.list;
4659 ctx.method = method;
4660 code_start = ip = ctx.header->code;
4661 end = ip + ctx.header->code_size;
4662 ctx.image = image = method->klass->image;
4665 ctx.max_args = ctx.signature->param_count + ctx.signature->hasthis;
4666 ctx.max_stack = ctx.header->max_stack;
4667 ctx.verifiable = ctx.valid = 1;
4668 ctx.level = level;
4670 ctx.code = g_new (ILCodeDesc, ctx.header->code_size);
4671 ctx.code_size = ctx.header->code_size;
4672 MEM_ALLOC (sizeof (ILCodeDesc) * ctx.header->code_size);
4674 memset(ctx.code, 0, sizeof (ILCodeDesc) * ctx.header->code_size);
4676 ctx.num_locals = ctx.header->num_locals;
4677 ctx.locals = g_memdup (ctx.header->locals, sizeof (MonoType*) * ctx.header->num_locals);
4678 MEM_ALLOC (sizeof (MonoType*) * ctx.header->num_locals);
4680 if (ctx.num_locals > 0 && !ctx.header->init_locals)
4681 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Method with locals variable but without init locals set"));
4683 ctx.params = g_new (MonoType*, ctx.max_args);
4684 MEM_ALLOC (sizeof (MonoType*) * ctx.max_args);
4686 if (ctx.signature->hasthis)
4687 ctx.params [0] = method->klass->valuetype ? &method->klass->this_arg : &method->klass->byval_arg;
4688 memcpy (ctx.params + ctx.signature->hasthis, ctx.signature->params, sizeof (MonoType *) * ctx.signature->param_count);
4690 if (ctx.signature->is_inflated)
4691 ctx.generic_context = generic_context = mono_method_get_context (method);
4693 if (!generic_context && (method->klass->generic_container || method->is_generic)) {
4694 if (method->is_generic)
4695 ctx.generic_context = generic_context = &(mono_method_get_generic_container (method)->context);
4696 else
4697 ctx.generic_context = generic_context = &method->klass->generic_container->context;
4700 for (i = 0; i < ctx.num_locals; ++i) {
4701 MonoType *uninflated = ctx.locals [i];
4702 ctx.locals [i] = mono_class_inflate_generic_type_checked (ctx.locals [i], ctx.generic_context, &error);
4703 if (!mono_error_ok (&error)) {
4704 char *name = mono_type_full_name (ctx.locals [i] ? ctx.locals [i] : uninflated);
4705 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %d of type %s", i, name));
4706 g_free (name);
4707 mono_error_cleanup (&error);
4708 /* we must not free (in cleanup) what was not yet allocated (but only copied) */
4709 ctx.num_locals = i;
4710 ctx.max_args = 0;
4711 goto cleanup;
4714 for (i = 0; i < ctx.max_args; ++i) {
4715 MonoType *uninflated = ctx.params [i];
4716 ctx.params [i] = mono_class_inflate_generic_type_checked (ctx.params [i], ctx.generic_context, &error);
4717 if (!mono_error_ok (&error)) {
4718 char *name = mono_type_full_name (ctx.params [i] ? ctx.params [i] : uninflated);
4719 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %d of type %s", i, name));
4720 g_free (name);
4721 mono_error_cleanup (&error);
4722 /* we must not free (in cleanup) what was not yet allocated (but only copied) */
4723 ctx.max_args = i;
4724 goto cleanup;
4727 stack_init (&ctx, &ctx.eval);
4729 for (i = 0; i < ctx.num_locals; ++i) {
4730 if (!mono_type_is_valid_in_context (&ctx, ctx.locals [i]))
4731 break;
4732 if (get_stack_type (ctx.locals [i]) == TYPE_INV) {
4733 char *name = mono_type_full_name (ctx.locals [i]);
4734 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %i of type %s", i, name));
4735 g_free (name);
4736 break;
4741 for (i = 0; i < ctx.max_args; ++i) {
4742 if (!mono_type_is_valid_in_context (&ctx, ctx.params [i]))
4743 break;
4745 if (get_stack_type (ctx.params [i]) == TYPE_INV) {
4746 char *name = mono_type_full_name (ctx.params [i]);
4747 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %i of type %s", i, name));
4748 g_free (name);
4749 break;
4753 if (!ctx.valid)
4754 goto cleanup;
4756 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
4757 MonoExceptionClause *clause = ctx.header->clauses + i;
4758 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); );
4760 if (clause->try_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, ctx.code_size))
4761 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause out of bounds at 0x%04x", clause->try_offset));
4763 if (clause->try_len <= 0)
4764 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause len <= 0 at 0x%04x", clause->try_offset));
4766 if (clause->handler_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->handler_offset, clause->handler_len, ctx.code_size))
4767 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause out of bounds at 0x%04x", clause->try_offset));
4769 if (clause->handler_len <= 0)
4770 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause len <= 0 at 0x%04x", clause->try_offset));
4772 if (clause->try_offset < clause->handler_offset && ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, HANDLER_START (clause)))
4773 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try block (at 0x%04x) includes handler block (at 0x%04x)", clause->try_offset, clause->handler_offset));
4775 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4776 if (clause->data.filter_offset > ctx.code_size)
4777 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause out of bounds at 0x%04x", clause->try_offset));
4779 if (clause->data.filter_offset >= clause->handler_offset)
4780 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause must come before the handler clause at 0x%04x", clause->data.filter_offset));
4783 for (n = i + 1; n < ctx.header->num_clauses && ctx.valid; ++n)
4784 verify_clause_relationship (&ctx, clause, ctx.header->clauses + n);
4786 if (!ctx.valid)
4787 break;
4789 ctx.code [clause->try_offset].flags |= IL_CODE_FLAG_WAS_TARGET;
4790 if (clause->try_offset + clause->try_len < ctx.code_size)
4791 ctx.code [clause->try_offset + clause->try_len].flags |= IL_CODE_FLAG_WAS_TARGET;
4792 if (clause->handler_offset + clause->handler_len < ctx.code_size)
4793 ctx.code [clause->handler_offset + clause->handler_len].flags |= IL_CODE_FLAG_WAS_TARGET;
4795 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
4796 if (!clause->data.catch_class) {
4797 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Catch clause %d with invalid type", i));
4798 break;
4801 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, clause->data.catch_class);
4803 else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4804 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->data.filter_offset, mono_defaults.exception_class);
4805 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, mono_defaults.exception_class);
4809 original_bb = bb = mono_basic_block_split (method, &error);
4810 if (!mono_error_ok (&error)) {
4811 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid branch target: %s", mono_error_get_message (&error)));
4812 mono_error_cleanup (&error);
4813 goto cleanup;
4815 g_assert (bb);
4817 while (ip < end && ctx.valid) {
4818 int op_size;
4819 ip_offset = ip - code_start;
4821 const unsigned char *ip_copy = ip;
4822 int op;
4824 if (ip_offset > bb->end) {
4825 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block at [0x%04x] targets middle instruction at 0x%04x", bb->end, ip_offset));
4826 goto cleanup;
4829 if (ip_offset == bb->end)
4830 bb = bb->next;
4832 op_size = mono_opcode_value_and_size (&ip_copy, end, &op);
4833 if (op_size == -1) {
4834 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ip_offset));
4835 goto cleanup;
4838 if (ADD_IS_GREATER_OR_OVF (ip_offset, op_size, bb->end)) {
4839 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block targets middle of instruction at 0x%04x", ip_offset));
4840 goto cleanup;
4843 /*Last Instruction*/
4844 if (ip_offset + op_size == bb->end && mono_opcode_is_prefix (op)) {
4845 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));
4846 goto cleanup;
4850 ctx.ip_offset = ip_offset = ip - code_start;
4852 /*We need to check against fallthrou in and out of protected blocks.
4853 * For fallout we check the once a protected block ends, if the start flag is not set.
4854 * Likewise for fallthru in, we check if ip is the start of a protected block and start is not set
4855 * TODO convert these checks to be done using flags and not this loop
4857 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
4858 MonoExceptionClause *clause = ctx.header->clauses + i;
4860 if ((clause->try_offset + clause->try_len == ip_offset) && start == 0) {
4861 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru off try block at 0x%04x", ip_offset));
4862 start = 1;
4865 if ((clause->handler_offset + clause->handler_len == ip_offset) && start == 0) {
4866 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
4867 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
4868 else
4869 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
4870 start = 1;
4873 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && clause->handler_offset == ip_offset && start == 0) {
4874 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of filter block at 0x%04x", ip_offset));
4875 start = 1;
4878 if (clause->handler_offset == ip_offset && start == 0) {
4879 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru handler block at 0x%04x", ip_offset));
4880 start = 1;
4883 if (clause->try_offset == ip_offset && ctx.eval.size > 0 && start == 0) {
4884 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Try to enter try block with a non-empty stack at 0x%04x", ip_offset));
4885 start = 1;
4889 /*This must be done after fallthru detection otherwise it won't happen.*/
4890 if (bb->dead) {
4891 /*FIXME remove this once we move all bad branch checking code to use BB only*/
4892 ctx.code [ip_offset].flags |= IL_CODE_FLAG_SEEN;
4893 ip += op_size;
4894 continue;
4897 if (!ctx.valid)
4898 break;
4900 if (need_merge) {
4901 VERIFIER_DEBUG ( printf ("extra merge needed! 0x%04x \n", ctx.target); );
4902 merge_stacks (&ctx, &ctx.eval, &ctx.code [ctx.target], FALSE, TRUE);
4903 need_merge = 0;
4905 merge_stacks (&ctx, &ctx.eval, &ctx.code[ip_offset], start, FALSE);
4906 start = 0;
4908 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
4909 #ifdef MONO_VERIFIER_DEBUG
4911 char *discode;
4912 discode = mono_disasm_code_one (NULL, method, ip, NULL);
4913 discode [strlen (discode) - 1] = 0; /* no \n */
4914 g_print ("[%d] %-29s (%d)\n", ip_offset, discode, ctx.eval.size);
4915 g_free (discode);
4917 dump_stack_state (&ctx.code [ip_offset]);
4918 dump_stack_state (&ctx.eval);
4919 #endif
4921 switch (*ip) {
4922 case CEE_NOP:
4923 case CEE_BREAK:
4924 ++ip;
4925 break;
4927 case CEE_LDARG_0:
4928 case CEE_LDARG_1:
4929 case CEE_LDARG_2:
4930 case CEE_LDARG_3:
4931 push_arg (&ctx, *ip - CEE_LDARG_0, FALSE);
4932 ++ip;
4933 break;
4935 case CEE_LDARG_S:
4936 case CEE_LDARGA_S:
4937 code_bounds_check (2);
4938 push_arg (&ctx, ip [1], *ip == CEE_LDARGA_S);
4939 ip += 2;
4940 break;
4942 case CEE_ADD_OVF_UN:
4943 do_binop (&ctx, *ip, add_ovf_un_table);
4944 ++ip;
4945 break;
4947 case CEE_SUB_OVF_UN:
4948 do_binop (&ctx, *ip, sub_ovf_un_table);
4949 ++ip;
4950 break;
4952 case CEE_ADD_OVF:
4953 case CEE_SUB_OVF:
4954 case CEE_MUL_OVF:
4955 case CEE_MUL_OVF_UN:
4956 do_binop (&ctx, *ip, bin_ovf_table);
4957 ++ip;
4958 break;
4960 case CEE_ADD:
4961 do_binop (&ctx, *ip, add_table);
4962 ++ip;
4963 break;
4965 case CEE_SUB:
4966 do_binop (&ctx, *ip, sub_table);
4967 ++ip;
4968 break;
4970 case CEE_MUL:
4971 case CEE_DIV:
4972 case CEE_REM:
4973 do_binop (&ctx, *ip, bin_op_table);
4974 ++ip;
4975 break;
4977 case CEE_AND:
4978 case CEE_DIV_UN:
4979 case CEE_OR:
4980 case CEE_REM_UN:
4981 case CEE_XOR:
4982 do_binop (&ctx, *ip, int_bin_op_table);
4983 ++ip;
4984 break;
4986 case CEE_SHL:
4987 case CEE_SHR:
4988 case CEE_SHR_UN:
4989 do_binop (&ctx, *ip, shift_op_table);
4990 ++ip;
4991 break;
4993 case CEE_POP:
4994 if (!check_underflow (&ctx, 1))
4995 break;
4996 stack_pop_safe (&ctx);
4997 ++ip;
4998 break;
5000 case CEE_RET:
5001 do_ret (&ctx);
5002 ++ip;
5003 start = 1;
5004 break;
5006 case CEE_LDLOC_0:
5007 case CEE_LDLOC_1:
5008 case CEE_LDLOC_2:
5009 case CEE_LDLOC_3:
5010 /*TODO support definite assignment verification? */
5011 push_local (&ctx, *ip - CEE_LDLOC_0, FALSE);
5012 ++ip;
5013 break;
5015 case CEE_STLOC_0:
5016 case CEE_STLOC_1:
5017 case CEE_STLOC_2:
5018 case CEE_STLOC_3:
5019 store_local (&ctx, *ip - CEE_STLOC_0);
5020 ++ip;
5021 break;
5023 case CEE_STLOC_S:
5024 code_bounds_check (2);
5025 store_local (&ctx, ip [1]);
5026 ip += 2;
5027 break;
5029 case CEE_STARG_S:
5030 code_bounds_check (2);
5031 store_arg (&ctx, ip [1]);
5032 ip += 2;
5033 break;
5035 case CEE_LDC_I4_M1:
5036 case CEE_LDC_I4_0:
5037 case CEE_LDC_I4_1:
5038 case CEE_LDC_I4_2:
5039 case CEE_LDC_I4_3:
5040 case CEE_LDC_I4_4:
5041 case CEE_LDC_I4_5:
5042 case CEE_LDC_I4_6:
5043 case CEE_LDC_I4_7:
5044 case CEE_LDC_I4_8:
5045 if (check_overflow (&ctx))
5046 stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
5047 ++ip;
5048 break;
5050 case CEE_LDC_I4_S:
5051 code_bounds_check (2);
5052 if (check_overflow (&ctx))
5053 stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
5054 ip += 2;
5055 break;
5057 case CEE_LDC_I4:
5058 code_bounds_check (5);
5059 if (check_overflow (&ctx))
5060 stack_push_val (&ctx,TYPE_I4, &mono_defaults.int32_class->byval_arg);
5061 ip += 5;
5062 break;
5064 case CEE_LDC_I8:
5065 code_bounds_check (9);
5066 if (check_overflow (&ctx))
5067 stack_push_val (&ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
5068 ip += 9;
5069 break;
5071 case CEE_LDC_R4:
5072 code_bounds_check (5);
5073 if (check_overflow (&ctx))
5074 stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
5075 ip += 5;
5076 break;
5078 case CEE_LDC_R8:
5079 code_bounds_check (9);
5080 if (check_overflow (&ctx))
5081 stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
5082 ip += 9;
5083 break;
5085 case CEE_LDNULL:
5086 if (check_overflow (&ctx))
5087 stack_push_val (&ctx, TYPE_COMPLEX | NULL_LITERAL_MASK, &mono_defaults.object_class->byval_arg);
5088 ++ip;
5089 break;
5091 case CEE_BEQ_S:
5092 case CEE_BNE_UN_S:
5093 code_bounds_check (2);
5094 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_eq_op);
5095 ip += 2;
5096 need_merge = 1;
5097 break;
5099 case CEE_BGE_S:
5100 case CEE_BGT_S:
5101 case CEE_BLE_S:
5102 case CEE_BLT_S:
5103 case CEE_BGE_UN_S:
5104 case CEE_BGT_UN_S:
5105 case CEE_BLE_UN_S:
5106 case CEE_BLT_UN_S:
5107 code_bounds_check (2);
5108 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_op);
5109 ip += 2;
5110 need_merge = 1;
5111 break;
5113 case CEE_BEQ:
5114 case CEE_BNE_UN:
5115 code_bounds_check (5);
5116 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_eq_op);
5117 ip += 5;
5118 need_merge = 1;
5119 break;
5121 case CEE_BGE:
5122 case CEE_BGT:
5123 case CEE_BLE:
5124 case CEE_BLT:
5125 case CEE_BGE_UN:
5126 case CEE_BGT_UN:
5127 case CEE_BLE_UN:
5128 case CEE_BLT_UN:
5129 code_bounds_check (5);
5130 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_op);
5131 ip += 5;
5132 need_merge = 1;
5133 break;
5135 case CEE_LDLOC_S:
5136 case CEE_LDLOCA_S:
5137 code_bounds_check (2);
5138 push_local (&ctx, ip[1], *ip == CEE_LDLOCA_S);
5139 ip += 2;
5140 break;
5142 case CEE_UNUSED99:
5143 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5144 ++ip;
5145 break;
5147 case CEE_DUP: {
5148 ILStackDesc *top;
5149 if (!check_underflow (&ctx, 1))
5150 break;
5151 if (!check_overflow (&ctx))
5152 break;
5153 top = stack_push (&ctx);
5154 copy_stack_value (top, stack_peek (&ctx, 1));
5155 ++ip;
5156 break;
5159 case CEE_JMP:
5160 code_bounds_check (5);
5161 if (ctx.eval.size)
5162 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Eval stack must be empty in jmp at 0x%04x", ip_offset));
5163 token = read32 (ip + 1);
5164 if (in_any_block (ctx.header, ip_offset))
5165 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("jmp cannot escape exception blocks at 0x%04x", ip_offset));
5167 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction jmp is not verifiable at 0x%04x", ctx.ip_offset));
5169 * FIXME: check signature, retval, arguments etc.
5171 ip += 5;
5172 break;
5173 case CEE_CALL:
5174 case CEE_CALLVIRT:
5175 code_bounds_check (5);
5176 do_invoke_method (&ctx, read32 (ip + 1), *ip == CEE_CALLVIRT);
5177 ip += 5;
5178 break;
5180 case CEE_CALLI:
5181 code_bounds_check (5);
5182 token = read32 (ip + 1);
5184 * FIXME: check signature, retval, arguments etc.
5185 * FIXME: check requirements for tail call
5187 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction calli is not verifiable at 0x%04x", ctx.ip_offset));
5188 ip += 5;
5189 break;
5190 case CEE_BR_S:
5191 code_bounds_check (2);
5192 do_static_branch (&ctx, (signed char)ip [1] + 2);
5193 need_merge = 1;
5194 ip += 2;
5195 start = 1;
5196 break;
5198 case CEE_BRFALSE_S:
5199 case CEE_BRTRUE_S:
5200 code_bounds_check (2);
5201 do_boolean_branch_op (&ctx, (signed char)ip [1] + 2);
5202 ip += 2;
5203 need_merge = 1;
5204 break;
5206 case CEE_BR:
5207 code_bounds_check (5);
5208 do_static_branch (&ctx, (gint32)read32 (ip + 1) + 5);
5209 need_merge = 1;
5210 ip += 5;
5211 start = 1;
5212 break;
5214 case CEE_BRFALSE:
5215 case CEE_BRTRUE:
5216 code_bounds_check (5);
5217 do_boolean_branch_op (&ctx, (gint32)read32 (ip + 1) + 5);
5218 ip += 5;
5219 need_merge = 1;
5220 break;
5222 case CEE_SWITCH: {
5223 guint32 entries;
5224 code_bounds_check (5);
5225 entries = read32 (ip + 1);
5227 if (entries > 0xFFFFFFFFU / sizeof (guint32))
5228 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Too many switch entries %x at 0x%04x", entries, ctx.ip_offset));
5230 ip += 5;
5231 code_bounds_check (sizeof (guint32) * entries);
5233 do_switch (&ctx, entries, ip);
5234 ip += sizeof (guint32) * entries;
5235 break;
5237 case CEE_LDIND_I1:
5238 case CEE_LDIND_U1:
5239 case CEE_LDIND_I2:
5240 case CEE_LDIND_U2:
5241 case CEE_LDIND_I4:
5242 case CEE_LDIND_U4:
5243 case CEE_LDIND_I8:
5244 case CEE_LDIND_I:
5245 case CEE_LDIND_R4:
5246 case CEE_LDIND_R8:
5247 case CEE_LDIND_REF:
5248 do_load_indirect (&ctx, *ip);
5249 ++ip;
5250 break;
5252 case CEE_STIND_REF:
5253 case CEE_STIND_I1:
5254 case CEE_STIND_I2:
5255 case CEE_STIND_I4:
5256 case CEE_STIND_I8:
5257 case CEE_STIND_R4:
5258 case CEE_STIND_R8:
5259 case CEE_STIND_I:
5260 do_store_indirect (&ctx, *ip);
5261 ++ip;
5262 break;
5264 case CEE_NOT:
5265 case CEE_NEG:
5266 do_unary_math_op (&ctx, *ip);
5267 ++ip;
5268 break;
5270 case CEE_CONV_I1:
5271 case CEE_CONV_I2:
5272 case CEE_CONV_I4:
5273 case CEE_CONV_U1:
5274 case CEE_CONV_U2:
5275 case CEE_CONV_U4:
5276 do_conversion (&ctx, TYPE_I4);
5277 ++ip;
5278 break;
5280 case CEE_CONV_I8:
5281 case CEE_CONV_U8:
5282 do_conversion (&ctx, TYPE_I8);
5283 ++ip;
5284 break;
5286 case CEE_CONV_R4:
5287 case CEE_CONV_R8:
5288 case CEE_CONV_R_UN:
5289 do_conversion (&ctx, TYPE_R8);
5290 ++ip;
5291 break;
5293 case CEE_CONV_I:
5294 case CEE_CONV_U:
5295 do_conversion (&ctx, TYPE_NATIVE_INT);
5296 ++ip;
5297 break;
5299 case CEE_CPOBJ:
5300 code_bounds_check (5);
5301 do_cpobj (&ctx, read32 (ip + 1));
5302 ip += 5;
5303 break;
5305 case CEE_LDOBJ:
5306 code_bounds_check (5);
5307 do_ldobj_value (&ctx, read32 (ip + 1));
5308 ip += 5;
5309 break;
5311 case CEE_LDSTR:
5312 code_bounds_check (5);
5313 do_ldstr (&ctx, read32 (ip + 1));
5314 ip += 5;
5315 break;
5317 case CEE_NEWOBJ:
5318 code_bounds_check (5);
5319 do_newobj (&ctx, read32 (ip + 1));
5320 ip += 5;
5321 break;
5323 case CEE_CASTCLASS:
5324 case CEE_ISINST:
5325 code_bounds_check (5);
5326 do_cast (&ctx, read32 (ip + 1), *ip == CEE_CASTCLASS ? "castclass" : "isinst");
5327 ip += 5;
5328 break;
5330 case CEE_UNUSED58:
5331 case CEE_UNUSED1:
5332 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5333 ++ip;
5334 break;
5336 case CEE_UNBOX:
5337 code_bounds_check (5);
5338 do_unbox_value (&ctx, read32 (ip + 1));
5339 ip += 5;
5340 break;
5342 case CEE_THROW:
5343 do_throw (&ctx);
5344 start = 1;
5345 ++ip;
5346 break;
5348 case CEE_LDFLD:
5349 case CEE_LDFLDA:
5350 code_bounds_check (5);
5351 do_push_field (&ctx, read32 (ip + 1), *ip == CEE_LDFLDA);
5352 ip += 5;
5353 break;
5355 case CEE_LDSFLD:
5356 case CEE_LDSFLDA:
5357 code_bounds_check (5);
5358 do_push_static_field (&ctx, read32 (ip + 1), *ip == CEE_LDSFLDA);
5359 ip += 5;
5360 break;
5362 case CEE_STFLD:
5363 code_bounds_check (5);
5364 do_store_field (&ctx, read32 (ip + 1));
5365 ip += 5;
5366 break;
5368 case CEE_STSFLD:
5369 code_bounds_check (5);
5370 do_store_static_field (&ctx, read32 (ip + 1));
5371 ip += 5;
5372 break;
5374 case CEE_STOBJ:
5375 code_bounds_check (5);
5376 do_stobj (&ctx, read32 (ip + 1));
5377 ip += 5;
5378 break;
5380 case CEE_CONV_OVF_I1_UN:
5381 case CEE_CONV_OVF_I2_UN:
5382 case CEE_CONV_OVF_I4_UN:
5383 case CEE_CONV_OVF_U1_UN:
5384 case CEE_CONV_OVF_U2_UN:
5385 case CEE_CONV_OVF_U4_UN:
5386 do_conversion (&ctx, TYPE_I4);
5387 ++ip;
5388 break;
5390 case CEE_CONV_OVF_I8_UN:
5391 case CEE_CONV_OVF_U8_UN:
5392 do_conversion (&ctx, TYPE_I8);
5393 ++ip;
5394 break;
5396 case CEE_CONV_OVF_I_UN:
5397 case CEE_CONV_OVF_U_UN:
5398 do_conversion (&ctx, TYPE_NATIVE_INT);
5399 ++ip;
5400 break;
5402 case CEE_BOX:
5403 code_bounds_check (5);
5404 do_box_value (&ctx, read32 (ip + 1));
5405 ip += 5;
5406 break;
5408 case CEE_NEWARR:
5409 code_bounds_check (5);
5410 do_newarr (&ctx, read32 (ip + 1));
5411 ip += 5;
5412 break;
5414 case CEE_LDLEN:
5415 do_ldlen (&ctx);
5416 ++ip;
5417 break;
5419 case CEE_LDELEMA:
5420 code_bounds_check (5);
5421 do_ldelema (&ctx, read32 (ip + 1));
5422 ip += 5;
5423 break;
5425 case CEE_LDELEM_I1:
5426 case CEE_LDELEM_U1:
5427 case CEE_LDELEM_I2:
5428 case CEE_LDELEM_U2:
5429 case CEE_LDELEM_I4:
5430 case CEE_LDELEM_U4:
5431 case CEE_LDELEM_I8:
5432 case CEE_LDELEM_I:
5433 case CEE_LDELEM_R4:
5434 case CEE_LDELEM_R8:
5435 case CEE_LDELEM_REF:
5436 do_ldelem (&ctx, *ip, 0);
5437 ++ip;
5438 break;
5440 case CEE_STELEM_I:
5441 case CEE_STELEM_I1:
5442 case CEE_STELEM_I2:
5443 case CEE_STELEM_I4:
5444 case CEE_STELEM_I8:
5445 case CEE_STELEM_R4:
5446 case CEE_STELEM_R8:
5447 case CEE_STELEM_REF:
5448 do_stelem (&ctx, *ip, 0);
5449 ++ip;
5450 break;
5452 case CEE_LDELEM:
5453 code_bounds_check (5);
5454 do_ldelem (&ctx, *ip, read32 (ip + 1));
5455 ip += 5;
5456 break;
5458 case CEE_STELEM:
5459 code_bounds_check (5);
5460 do_stelem (&ctx, *ip, read32 (ip + 1));
5461 ip += 5;
5462 break;
5464 case CEE_UNBOX_ANY:
5465 code_bounds_check (5);
5466 do_unbox_any (&ctx, read32 (ip + 1));
5467 ip += 5;
5468 break;
5470 case CEE_CONV_OVF_I1:
5471 case CEE_CONV_OVF_U1:
5472 case CEE_CONV_OVF_I2:
5473 case CEE_CONV_OVF_U2:
5474 case CEE_CONV_OVF_I4:
5475 case CEE_CONV_OVF_U4:
5476 do_conversion (&ctx, TYPE_I4);
5477 ++ip;
5478 break;
5480 case CEE_CONV_OVF_I8:
5481 case CEE_CONV_OVF_U8:
5482 do_conversion (&ctx, TYPE_I8);
5483 ++ip;
5484 break;
5486 case CEE_CONV_OVF_I:
5487 case CEE_CONV_OVF_U:
5488 do_conversion (&ctx, TYPE_NATIVE_INT);
5489 ++ip;
5490 break;
5492 case CEE_REFANYVAL:
5493 code_bounds_check (5);
5494 do_refanyval (&ctx, read32 (ip + 1));
5495 ip += 5;
5496 break;
5498 case CEE_CKFINITE:
5499 do_ckfinite (&ctx);
5500 ++ip;
5501 break;
5503 case CEE_MKREFANY:
5504 code_bounds_check (5);
5505 do_mkrefany (&ctx, read32 (ip + 1));
5506 ip += 5;
5507 break;
5509 case CEE_LDTOKEN:
5510 code_bounds_check (5);
5511 do_load_token (&ctx, read32 (ip + 1));
5512 ip += 5;
5513 break;
5515 case CEE_ENDFINALLY:
5516 if (!is_correct_endfinally (ctx.header, ip_offset))
5517 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("endfinally must be used inside a finally/fault handler at 0x%04x", ctx.ip_offset));
5518 ctx.eval.size = 0;
5519 start = 1;
5520 ++ip;
5521 break;
5523 case CEE_LEAVE:
5524 code_bounds_check (5);
5525 do_leave (&ctx, read32 (ip + 1) + 5);
5526 ip += 5;
5527 start = 1;
5528 need_merge = 1;
5529 break;
5531 case CEE_LEAVE_S:
5532 code_bounds_check (2);
5533 do_leave (&ctx, (signed char)ip [1] + 2);
5534 ip += 2;
5535 start = 1;
5536 need_merge = 1;
5537 break;
5539 case CEE_PREFIX1:
5540 code_bounds_check (2);
5541 ++ip;
5542 switch (*ip) {
5543 case CEE_STLOC:
5544 code_bounds_check (3);
5545 store_local (&ctx, read16 (ip + 1));
5546 ip += 3;
5547 break;
5549 case CEE_CEQ:
5550 do_cmp_op (&ctx, cmp_br_eq_op, *ip);
5551 ++ip;
5552 break;
5554 case CEE_CGT:
5555 case CEE_CGT_UN:
5556 case CEE_CLT:
5557 case CEE_CLT_UN:
5558 do_cmp_op (&ctx, cmp_br_op, *ip);
5559 ++ip;
5560 break;
5562 case CEE_STARG:
5563 code_bounds_check (3);
5564 store_arg (&ctx, read16 (ip + 1) );
5565 ip += 3;
5566 break;
5569 case CEE_ARGLIST:
5570 if (!check_overflow (&ctx))
5571 break;
5572 if (ctx.signature->call_convention != MONO_CALL_VARARG)
5573 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot use arglist on method without VARGARG calling convention at 0x%04x", ctx.ip_offset));
5574 set_stack_value (&ctx, stack_push (&ctx), &mono_defaults.argumenthandle_class->byval_arg, FALSE);
5575 ++ip;
5576 break;
5578 case CEE_LDFTN:
5579 code_bounds_check (5);
5580 do_load_function_ptr (&ctx, read32 (ip + 1), FALSE);
5581 ip += 5;
5582 break;
5584 case CEE_LDVIRTFTN:
5585 code_bounds_check (5);
5586 do_load_function_ptr (&ctx, read32 (ip + 1), TRUE);
5587 ip += 5;
5588 break;
5590 case CEE_LDARG:
5591 case CEE_LDARGA:
5592 code_bounds_check (3);
5593 push_arg (&ctx, read16 (ip + 1), *ip == CEE_LDARGA);
5594 ip += 3;
5595 break;
5597 case CEE_LDLOC:
5598 case CEE_LDLOCA:
5599 code_bounds_check (3);
5600 push_local (&ctx, read16 (ip + 1), *ip == CEE_LDLOCA);
5601 ip += 3;
5602 break;
5604 case CEE_LOCALLOC:
5605 do_localloc (&ctx);
5606 ++ip;
5607 break;
5609 case CEE_UNUSED56:
5610 case CEE_UNUSED57:
5611 case CEE_UNUSED70:
5612 case CEE_UNUSED:
5613 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5614 ++ip;
5615 break;
5616 case CEE_ENDFILTER:
5617 do_endfilter (&ctx);
5618 start = 1;
5619 ++ip;
5620 break;
5621 case CEE_UNALIGNED_:
5622 code_bounds_check (2);
5623 prefix |= PREFIX_UNALIGNED;
5624 ip += 2;
5625 break;
5626 case CEE_VOLATILE_:
5627 prefix |= PREFIX_VOLATILE;
5628 ++ip;
5629 break;
5630 case CEE_TAIL_:
5631 prefix |= PREFIX_TAIL;
5632 ++ip;
5633 if (ip < end && (*ip != CEE_CALL && *ip != CEE_CALLI && *ip != CEE_CALLVIRT))
5634 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("tail prefix must be used only with call opcodes at 0x%04x", ip_offset));
5635 break;
5637 case CEE_INITOBJ:
5638 code_bounds_check (5);
5639 do_initobj (&ctx, read32 (ip + 1));
5640 ip += 5;
5641 break;
5643 case CEE_CONSTRAINED_:
5644 code_bounds_check (5);
5645 ctx.constrained_type = get_boxable_mono_type (&ctx, read32 (ip + 1), "constrained.");
5646 prefix |= PREFIX_CONSTRAINED;
5647 ip += 5;
5648 break;
5650 case CEE_READONLY_:
5651 prefix |= PREFIX_READONLY;
5652 ip++;
5653 break;
5655 case CEE_CPBLK:
5656 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5657 if (!check_underflow (&ctx, 3))
5658 break;
5659 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction cpblk is not verifiable at 0x%04x", ctx.ip_offset));
5660 ip++;
5661 break;
5663 case CEE_INITBLK:
5664 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5665 if (!check_underflow (&ctx, 3))
5666 break;
5667 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction initblk is not verifiable at 0x%04x", ctx.ip_offset));
5668 ip++;
5669 break;
5671 case CEE_NO_:
5672 ip += 2;
5673 break;
5674 case CEE_RETHROW:
5675 if (!is_correct_rethrow (ctx.header, ip_offset))
5676 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("rethrow must be used inside a catch handler at 0x%04x", ctx.ip_offset));
5677 ctx.eval.size = 0;
5678 start = 1;
5679 ++ip;
5680 break;
5682 case CEE_SIZEOF:
5683 code_bounds_check (5);
5684 do_sizeof (&ctx, read32 (ip + 1));
5685 ip += 5;
5686 break;
5688 case CEE_REFANYTYPE:
5689 do_refanytype (&ctx);
5690 ++ip;
5691 break;
5693 default:
5694 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction FE %x at 0x%04x", *ip, ctx.ip_offset));
5695 ++ip;
5697 break;
5699 default:
5700 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ctx.ip_offset));
5701 ++ip;
5704 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
5705 if (prefix) {
5706 if (!ctx.prefix_set) //first prefix
5707 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
5708 ctx.prefix_set |= prefix;
5709 ctx.has_flags = TRUE;
5710 prefix = 0;
5711 } else {
5712 if (!ctx.has_flags)
5713 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
5715 if (ctx.prefix_set & PREFIX_CONSTRAINED)
5716 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after constrained prefix at 0x%04x", ctx.ip_offset));
5717 if (ctx.prefix_set & PREFIX_READONLY)
5718 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after readonly prefix at 0x%04x", ctx.ip_offset));
5719 if (ctx.prefix_set & PREFIX_VOLATILE)
5720 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after volatile prefix at 0x%04x", ctx.ip_offset));
5721 if (ctx.prefix_set & PREFIX_UNALIGNED)
5722 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after unaligned prefix at 0x%04x", ctx.ip_offset));
5723 ctx.prefix_set = prefix = 0;
5724 ctx.has_flags = FALSE;
5728 * if ip != end we overflowed: mark as error.
5730 if ((ip != end || !start) && ctx.verifiable && !ctx.list) {
5731 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Run ahead of method code at 0x%04x", ip_offset));
5734 /*We should guard against the last decoded opcode, otherwise we might add errors that doesn't make sense.*/
5735 for (i = 0; i < ctx.code_size && i < ip_offset; ++i) {
5736 if (ctx.code [i].flags & IL_CODE_FLAG_WAS_TARGET) {
5737 if (!(ctx.code [i].flags & IL_CODE_FLAG_SEEN))
5738 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or exception block target middle of intruction at 0x%04x", i));
5740 if (ctx.code [i].flags & IL_CODE_DELEGATE_SEQUENCE)
5741 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Branch to delegate code sequence at 0x%04x", i));
5743 if ((ctx.code [i].flags & IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL) && ctx.has_this_store)
5744 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at 0x%04x", i));
5746 if ((ctx.code [i].flags & IL_CODE_CALL_NONFINAL_VIRTUAL) && ctx.has_this_store)
5747 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));
5750 if (mono_method_is_constructor (ctx.method) && !ctx.super_ctor_called && !ctx.method->klass->valuetype && ctx.method->klass != mono_defaults.object_class) {
5751 char *method_name = mono_method_full_name (ctx.method, TRUE);
5752 char *type = mono_type_get_full_name (ctx.method->klass);
5753 if (ctx.method->klass->parent && ctx.method->klass->parent->exception_type != MONO_EXCEPTION_NONE)
5754 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));
5755 else
5756 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Constructor %s for type %s not calling base type ctor.", method_name, type));
5757 g_free (method_name);
5758 g_free (type);
5761 cleanup:
5762 if (ctx.code) {
5763 for (i = 0; i < ctx.header->code_size; ++i) {
5764 if (ctx.code [i].stack)
5765 g_free (ctx.code [i].stack);
5769 for (tmp = ctx.funptrs; tmp; tmp = tmp->next)
5770 g_free (tmp->data);
5771 g_slist_free (ctx.funptrs);
5773 for (tmp = ctx.exception_types; tmp; tmp = tmp->next)
5774 mono_metadata_free_type (tmp->data);
5775 g_slist_free (ctx.exception_types);
5777 for (i = 0; i < ctx.num_locals; ++i) {
5778 if (ctx.locals [i])
5779 mono_metadata_free_type (ctx.locals [i]);
5781 for (i = 0; i < ctx.max_args; ++i) {
5782 if (ctx.params [i])
5783 mono_metadata_free_type (ctx.params [i]);
5786 if (ctx.eval.stack)
5787 g_free (ctx.eval.stack);
5788 if (ctx.code)
5789 g_free (ctx.code);
5790 g_free (ctx.locals);
5791 g_free (ctx.params);
5792 mono_basic_block_free (original_bb);
5793 mono_metadata_free_mh (ctx.header);
5795 finish_collect_stats ();
5796 return ctx.list;
5799 char*
5800 mono_verify_corlib ()
5802 /* This is a public API function so cannot be removed */
5803 return NULL;
5807 * Returns true if @method needs to be verified.
5810 gboolean
5811 mono_verifier_is_enabled_for_method (MonoMethod *method)
5813 return mono_verifier_is_enabled_for_class (method->klass) && (method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD);
5817 * Returns true if @klass need to be verified.
5820 gboolean
5821 mono_verifier_is_enabled_for_class (MonoClass *klass)
5823 return verify_all || (verifier_mode > MONO_VERIFIER_MODE_OFF && !(klass->image->assembly && klass->image->assembly->in_gac) && klass->image != mono_defaults.corlib);
5826 gboolean
5827 mono_verifier_is_enabled_for_image (MonoImage *image)
5829 return verify_all || verifier_mode > MONO_VERIFIER_MODE_OFF;
5833 * Dynamic methods are not considered full trust since if the user is trusted and need to
5834 * generate unsafe code, make the method skip verification - this is a known good way to do it.
5836 gboolean
5837 mono_verifier_is_method_full_trust (MonoMethod *method)
5839 return mono_verifier_is_class_full_trust (method->klass) && !method->dynamic;
5843 * Returns if @klass is under full trust or not.
5845 * TODO This code doesn't take CAS into account.
5847 * Under verify_all all user code must be verifiable if no security option was set
5850 gboolean
5851 mono_verifier_is_class_full_trust (MonoClass *klass)
5853 /* under CoreCLR code is trusted if it is part of the "platform" otherwise all code inside the GAC is trusted */
5854 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
5855 (klass->image->assembly && klass->image->assembly->in_gac) : mono_security_core_clr_is_platform_image (klass->image);
5857 if (verify_all && verifier_mode == MONO_VERIFIER_MODE_OFF)
5858 return trusted_location || klass->image == mono_defaults.corlib;
5859 return verifier_mode < MONO_VERIFIER_MODE_VERIFIABLE || trusted_location || klass->image == mono_defaults.corlib;
5862 GSList*
5863 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility)
5865 return mono_method_verify (method,
5866 (verifier_mode != MONO_VERIFIER_MODE_STRICT ? MONO_VERIFY_NON_STRICT: 0)
5867 | (!mono_verifier_is_method_full_trust (method) ? MONO_VERIFY_FAIL_FAST : 0)
5868 | (skip_visibility ? MONO_VERIFY_SKIP_VISIBILITY : 0));
5871 static int
5872 get_field_end (MonoClassField *field)
5874 int align;
5875 int size = mono_type_size (field->type, &align);
5876 if (size == 0)
5877 size = 4; /*FIXME Is this a safe bet?*/
5878 return size + field->offset;
5881 static gboolean
5882 verify_class_for_overlapping_reference_fields (MonoClass *class)
5884 int i = 0, j;
5885 gpointer iter = NULL;
5886 MonoClassField *field;
5887 gboolean is_fulltrust = mono_verifier_is_class_full_trust (class);
5888 /*We can't skip types with !has_references since this is calculated after we have run.*/
5889 if (!((class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT))
5890 return TRUE;
5893 /*We must check for stuff overlapping reference fields.
5894 The outer loop uses mono_class_get_fields to ensure that MonoClass:fields get inited.
5896 while ((field = mono_class_get_fields (class, &iter))) {
5897 int fieldEnd = get_field_end (field);
5898 gboolean is_valuetype = !MONO_TYPE_IS_REFERENCE (field->type);
5899 ++i;
5901 if (mono_field_is_deleted (field) || (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
5902 continue;
5904 for (j = i; j < class->field.count; ++j) {
5905 MonoClassField *other = &class->fields [j];
5906 int otherEnd = get_field_end (other);
5907 if (mono_field_is_deleted (other) || (is_valuetype && !MONO_TYPE_IS_REFERENCE (other->type)) || (other->type->attrs & FIELD_ATTRIBUTE_STATIC))
5908 continue;
5910 if (!is_valuetype && MONO_TYPE_IS_REFERENCE (other->type) && field->offset == other->offset && is_fulltrust)
5911 continue;
5913 if ((otherEnd > field->offset && otherEnd <= fieldEnd) || (other->offset >= field->offset && other->offset < fieldEnd))
5914 return FALSE;
5917 return TRUE;
5920 static guint
5921 field_hash (gconstpointer key)
5923 const MonoClassField *field = key;
5924 return g_str_hash (field->name) ^ mono_metadata_type_hash (field->type); /**/
5927 static gboolean
5928 field_equals (gconstpointer _a, gconstpointer _b)
5930 const MonoClassField *a = _a;
5931 const MonoClassField *b = _b;
5932 return !strcmp (a->name, b->name) && mono_metadata_type_equal (a->type, b->type);
5936 static gboolean
5937 verify_class_fields (MonoClass *class)
5939 gpointer iter = NULL;
5940 MonoClassField *field;
5941 MonoGenericContext *context = mono_class_get_context (class);
5942 GHashTable *unique_fields = g_hash_table_new_full (&field_hash, &field_equals, NULL, NULL);
5943 if (class->generic_container)
5944 context = &class->generic_container->context;
5946 while ((field = mono_class_get_fields (class, &iter)) != NULL) {
5947 if (!mono_type_is_valid_type_in_context (field->type, context)) {
5948 g_hash_table_destroy (unique_fields);
5949 return FALSE;
5951 if (g_hash_table_lookup (unique_fields, field)) {
5952 g_hash_table_destroy (unique_fields);
5953 return FALSE;
5955 g_hash_table_insert (unique_fields, field, field);
5957 g_hash_table_destroy (unique_fields);
5958 return TRUE;
5961 static gboolean
5962 verify_interfaces (MonoClass *class)
5964 int i;
5965 for (i = 0; i < class->interface_count; ++i) {
5966 MonoClass *iface = class->interfaces [i];
5967 if (!(iface->flags & TYPE_ATTRIBUTE_INTERFACE))
5968 return FALSE;
5970 return TRUE;
5973 static gboolean
5974 verify_valuetype_layout_with_target (MonoClass *class, MonoClass *target_class)
5976 int type;
5977 gpointer iter = NULL;
5978 MonoClassField *field;
5979 MonoClass *field_class;
5981 if (!class->valuetype)
5982 return TRUE;
5984 type = class->byval_arg.type;
5985 /*primitive type fields are not properly decoded*/
5986 if ((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_R8) || (type >= MONO_TYPE_I && type <= MONO_TYPE_U))
5987 return TRUE;
5989 while ((field = mono_class_get_fields (class, &iter)) != NULL) {
5990 if (!field->type)
5991 return FALSE;
5993 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
5994 continue;
5996 field_class = mono_class_get_generic_type_definition (mono_class_from_mono_type (field->type));
5998 if (field_class == target_class || class == field_class || !verify_valuetype_layout_with_target (field_class, target_class))
5999 return FALSE;
6002 return TRUE;
6005 static gboolean
6006 verify_valuetype_layout (MonoClass *class)
6008 gboolean res;
6009 res = verify_valuetype_layout_with_target (class, class);
6010 return res;
6013 static gboolean
6014 recursive_mark_constraint_args (MonoBitSet *used_args, MonoGenericContainer *gc, MonoType *type)
6016 int idx;
6017 MonoClass **constraints;
6018 MonoGenericParamInfo *param_info;
6020 g_assert (mono_type_is_generic_argument (type));
6022 idx = mono_type_get_generic_param_num (type);
6023 if (mono_bitset_test_fast (used_args, idx))
6024 return FALSE;
6026 mono_bitset_set_fast (used_args, idx);
6027 param_info = mono_generic_container_get_param_info (gc, idx);
6029 if (!param_info->constraints)
6030 return TRUE;
6032 for (constraints = param_info->constraints; *constraints; ++constraints) {
6033 MonoClass *ctr = *constraints;
6034 MonoType *constraint_type = &ctr->byval_arg;
6036 if (mono_type_is_generic_argument (constraint_type) && !recursive_mark_constraint_args (used_args, gc, constraint_type))
6037 return FALSE;
6039 return TRUE;
6042 static gboolean
6043 verify_generic_parameters (MonoClass *class)
6045 int i;
6046 MonoGenericContainer *gc = class->generic_container;
6047 MonoBitSet *used_args = mono_bitset_new (gc->type_argc, 0);
6049 for (i = 0; i < gc->type_argc; ++i) {
6050 MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
6051 MonoClass **constraints;
6053 if (!param_info->constraints)
6054 continue;
6056 mono_bitset_clear_all (used_args);
6057 mono_bitset_set_fast (used_args, i);
6059 for (constraints = param_info->constraints; *constraints; ++constraints) {
6060 MonoClass *ctr = *constraints;
6061 MonoType *constraint_type = &ctr->byval_arg;
6063 if (!mono_type_is_valid_type_in_context (constraint_type, &gc->context))
6064 goto fail;
6066 if (mono_type_is_generic_argument (constraint_type) && !recursive_mark_constraint_args (used_args, gc, constraint_type))
6067 goto fail;
6068 if (ctr->generic_class && !mono_class_is_valid_generic_instantiation (NULL, ctr))
6069 goto fail;
6072 mono_bitset_free (used_args);
6073 return TRUE;
6075 fail:
6076 mono_bitset_free (used_args);
6077 return FALSE;
6081 * Check if the class is verifiable.
6083 * Right now there are no conditions that make a class a valid but not verifiable. Both overlapping reference
6084 * field and invalid generic instantiation are fatal errors.
6086 * This method must be safe to be called from mono_class_init and all code must be carefull about that.
6089 gboolean
6090 mono_verifier_verify_class (MonoClass *class)
6092 /*Neither <Module>, object or ifaces have parent.*/
6093 if (!class->parent &&
6094 class != mono_defaults.object_class &&
6095 !MONO_CLASS_IS_INTERFACE (class) &&
6096 (!class->image->dynamic && class->type_token != 0x2000001)) /*<Module> is the first type in the assembly*/
6097 return FALSE;
6098 if (class->parent) {
6099 if (MONO_CLASS_IS_INTERFACE (class->parent))
6100 return FALSE;
6101 if (!class->generic_class && class->parent->generic_container)
6102 return FALSE;
6104 if (class->generic_container && (class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT)
6105 return FALSE;
6106 if (class->generic_container && !verify_generic_parameters (class))
6107 return FALSE;
6108 if (!verify_class_for_overlapping_reference_fields (class))
6109 return FALSE;
6110 if (class->generic_class && !mono_class_is_valid_generic_instantiation (NULL, class))
6111 return FALSE;
6112 if (class->generic_class == NULL && !verify_class_fields (class))
6113 return FALSE;
6114 if (class->valuetype && !verify_valuetype_layout (class))
6115 return FALSE;
6116 if (!verify_interfaces (class))
6117 return FALSE;
6118 return TRUE;
6121 gboolean
6122 mono_verifier_class_is_valid_generic_instantiation (MonoClass *class)
6124 return mono_class_is_valid_generic_instantiation (NULL, class);
6127 gboolean
6128 mono_verifier_is_method_valid_generic_instantiation (MonoMethod *method)
6130 if (!method->is_inflated)
6131 return TRUE;
6132 return mono_method_is_valid_generic_instantiation (NULL, method);
6135 #else
6137 gboolean
6138 mono_verifier_verify_class (MonoClass *class)
6140 /* The verifier was disabled at compile time */
6141 return TRUE;
6144 GSList*
6145 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility)
6147 /* The verifier was disabled at compile time */
6148 return NULL;
6151 gboolean
6152 mono_verifier_is_class_full_trust (MonoClass *klass)
6154 /* The verifier was disabled at compile time */
6155 return TRUE;
6158 gboolean
6159 mono_verifier_is_method_full_trust (MonoMethod *method)
6161 /* The verifier was disabled at compile time */
6162 return TRUE;
6165 gboolean
6166 mono_verifier_is_enabled_for_image (MonoImage *image)
6168 /* The verifier was disabled at compile time */
6169 return FALSE;
6172 gboolean
6173 mono_verifier_is_enabled_for_class (MonoClass *klass)
6175 /* The verifier was disabled at compile time */
6176 return FALSE;
6179 gboolean
6180 mono_verifier_is_enabled_for_method (MonoMethod *method)
6182 /* The verifier was disabled at compile time */
6183 return FALSE;
6186 GSList*
6187 mono_method_verify (MonoMethod *method, int level)
6189 /* The verifier was disabled at compile time */
6190 return NULL;
6193 void
6194 mono_free_verify_list (GSList *list)
6196 /* The verifier was disabled at compile time */
6197 /* will always be null if verifier is disabled */
6200 gboolean
6201 mono_verifier_class_is_valid_generic_instantiation (MonoClass *class)
6203 return TRUE;
6206 gboolean
6207 mono_verifier_is_method_valid_generic_instantiation (MonoMethod *method)
6209 return TRUE;
6214 #endif