[runtime] Require C# namespace to be quoted.
[mono-project.git] / mono / metadata / verify.c
blobf826b7965e77f86719fd45b5d15f4545286801b0
1 /*
2 * verify.c:
4 * Author:
5 * Mono Project (http://www.mono-project.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Rodrigo Kumpera
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12 #include <config.h>
14 #include <mono/metadata/object-internals.h>
15 #include <mono/metadata/dynamic-image-internals.h>
16 #include <mono/metadata/verify.h>
17 #include <mono/metadata/verify-internals.h>
18 #include <mono/metadata/opcodes.h>
19 #include <mono/metadata/tabledefs.h>
20 #include <mono/metadata/reflection.h>
21 #include <mono/metadata/debug-helpers.h>
22 #include <mono/metadata/mono-endian.h>
23 #include <mono/metadata/metadata.h>
24 #include <mono/metadata/metadata-internals.h>
25 #include <mono/metadata/class-internals.h>
26 #include <mono/metadata/security-manager.h>
27 #include <mono/metadata/security-core-clr.h>
28 #include <mono/metadata/tokentype.h>
29 #include <mono/metadata/mono-basic-block.h>
30 #include <mono/metadata/attrdefs.h>
31 #include <mono/utils/mono-counters.h>
32 #include <mono/utils/monobitset.h>
33 #include <string.h>
34 #include <ctype.h>
36 static MiniVerifierMode verifier_mode = MONO_VERIFIER_MODE_OFF;
37 static gboolean verify_all = FALSE;
40 * Set the desired level of checks for the verfier.
43 void
44 mono_verifier_set_mode (MiniVerifierMode mode)
46 verifier_mode = mode;
49 void
50 mono_verifier_enable_verify_all ()
52 verify_all = TRUE;
55 #ifndef DISABLE_VERIFIER
57 * Pull the list of opcodes
59 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
60 a = i,
62 enum {
63 #include "mono/cil/opcode.def"
64 LAST = 0xff
66 #undef OPDEF
68 #ifdef MONO_VERIFIER_DEBUG
69 #define VERIFIER_DEBUG(code) do { code } while (0)
70 #else
71 #define VERIFIER_DEBUG(code)
72 #endif
74 //////////////////////////////////////////////////////////////////
75 #define IS_STRICT_MODE(ctx) (((ctx)->level & MONO_VERIFY_NON_STRICT) == 0)
76 #define IS_FAIL_FAST_MODE(ctx) (((ctx)->level & MONO_VERIFY_FAIL_FAST) == MONO_VERIFY_FAIL_FAST)
77 #define IS_SKIP_VISIBILITY(ctx) (((ctx)->level & MONO_VERIFY_SKIP_VISIBILITY) == MONO_VERIFY_SKIP_VISIBILITY)
78 #define IS_REPORT_ALL_ERRORS(ctx) (((ctx)->level & MONO_VERIFY_REPORT_ALL_ERRORS) == MONO_VERIFY_REPORT_ALL_ERRORS)
79 #define CLEAR_PREFIX(ctx, prefix) do { (ctx)->prefix_set &= ~(prefix); } while (0)
80 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
81 do { \
82 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
83 vinfo->info.status = __status; \
84 vinfo->info.message = ( __msg ); \
85 vinfo->exception_type = (__exception); \
86 (__ctx)->list = g_slist_prepend ((__ctx)->list, vinfo); \
87 } while (0)
89 //TODO support MONO_VERIFY_REPORT_ALL_ERRORS
90 #define ADD_VERIFY_ERROR(__ctx, __msg) \
91 do { \
92 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
93 (__ctx)->valid = 0; \
94 } while (0)
96 #define CODE_NOT_VERIFIABLE(__ctx, __msg) \
97 do { \
98 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
99 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, MONO_EXCEPTION_UNVERIFIABLE_IL); \
100 (__ctx)->verifiable = 0; \
101 if (IS_FAIL_FAST_MODE (__ctx)) \
102 (__ctx)->valid = 0; \
104 } while (0)
106 #define ADD_VERIFY_ERROR2(__ctx, __msg, __exception) \
107 do { \
108 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, __exception); \
109 (__ctx)->valid = 0; \
110 } while (0)
112 #define CODE_NOT_VERIFIABLE2(__ctx, __msg, __exception) \
113 do { \
114 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
115 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, __exception); \
116 (__ctx)->verifiable = 0; \
117 if (IS_FAIL_FAST_MODE (__ctx)) \
118 (__ctx)->valid = 0; \
120 } while (0)
122 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
123 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
125 #if SIZEOF_VOID_P == 4
126 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
127 #else
128 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
129 #endif
131 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
132 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
134 /*Flags to be used with ILCodeDesc::flags */
135 enum {
136 /*Instruction has not been processed.*/
137 IL_CODE_FLAG_NOT_PROCESSED = 0,
138 /*Instruction was decoded by mono_method_verify loop.*/
139 IL_CODE_FLAG_SEEN = 1,
140 /*Instruction was target of a branch or is at a protected block boundary.*/
141 IL_CODE_FLAG_WAS_TARGET = 2,
142 /*Used by stack_init to avoid double initialize each entry.*/
143 IL_CODE_FLAG_STACK_INITED = 4,
144 /*Used by merge_stacks to decide if it should just copy the eval stack.*/
145 IL_CODE_STACK_MERGED = 8,
146 /*This instruction is part of the delegate construction sequence, it cannot be target of a branch.*/
147 IL_CODE_DELEGATE_SEQUENCE = 0x10,
148 /*This is a delegate created from a ldftn to a non final virtual method*/
149 IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL = 0x20,
150 /*This is a call to a non final virtual method*/
151 IL_CODE_CALL_NONFINAL_VIRTUAL = 0x40,
154 typedef enum {
155 RESULT_VALID,
156 RESULT_UNVERIFIABLE,
157 RESULT_INVALID
158 } verify_result_t;
160 typedef struct {
161 MonoType *type;
162 int stype;
163 MonoMethod *method;
164 } ILStackDesc;
167 typedef struct {
168 ILStackDesc *stack;
169 guint16 size, max_size;
170 guint16 flags;
171 } ILCodeDesc;
173 typedef struct {
174 int max_args;
175 int max_stack;
176 int verifiable;
177 int valid;
178 int level;
180 int code_size;
181 ILCodeDesc *code;
182 ILCodeDesc eval;
184 MonoType **params;
185 GSList *list;
186 /*Allocated fnptr MonoType that should be freed by us.*/
187 GSList *funptrs;
188 /*Type dup'ed exception types from catch blocks.*/
189 GSList *exception_types;
191 int num_locals;
192 MonoType **locals;
194 /*TODO get rid of target here, need_merge in mono_method_verify and hoist the merging code in the branching code*/
195 int target;
197 guint32 ip_offset;
198 MonoMethodSignature *signature;
199 MonoMethodHeader *header;
201 MonoGenericContext *generic_context;
202 MonoImage *image;
203 MonoMethod *method;
205 /*This flag helps solving a corner case of delegate verification in that you cannot have a "starg 0"
206 *on a method that creates a delegate for a non-final virtual method using ldftn*/
207 gboolean has_this_store;
209 /*This flag is used to control if the contructor of the parent class has been called.
210 *If the this pointer is pushed on the eval stack and it's a reference type constructor and
211 * super_ctor_called is false, the uninitialized flag is set on the pushed value.
213 * Poping an uninitialized this ptr from the eval stack is an unverifiable operation unless
214 * the safe variant is used. Only a few opcodes can use it : dup, pop, ldfld, stfld and call to a constructor.
216 gboolean super_ctor_called;
218 guint32 prefix_set;
219 gboolean has_flags;
220 MonoType *constrained_type;
221 } VerifyContext;
223 static void
224 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external);
226 static int
227 get_stack_type (MonoType *type);
229 static gboolean
230 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn);
232 static gboolean
233 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass);
235 static gboolean
236 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method);
238 static MonoGenericParam*
239 verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type);
241 static gboolean
242 verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate);
243 //////////////////////////////////////////////////////////////////
247 enum {
248 TYPE_INV = 0, /* leave at 0. */
249 TYPE_I4 = 1,
250 TYPE_I8 = 2,
251 TYPE_NATIVE_INT = 3,
252 TYPE_R8 = 4,
253 /* Used by operator tables to resolve pointer types (managed & unmanaged) and by unmanaged pointer types*/
254 TYPE_PTR = 5,
255 /* value types and classes */
256 TYPE_COMPLEX = 6,
257 /* Number of types, used to define the size of the tables*/
258 TYPE_MAX = 6,
260 /* Used by tables to signal that a result is not verifiable*/
261 NON_VERIFIABLE_RESULT = 0x80,
263 /*Mask used to extract just the type, excluding flags */
264 TYPE_MASK = 0x0F,
266 /* The stack type is a managed pointer, unmask the value to res */
267 POINTER_MASK = 0x100,
269 /*Stack type with the pointer mask*/
270 RAW_TYPE_MASK = 0x10F,
272 /* Controlled Mutability Manager Pointer */
273 CMMP_MASK = 0x200,
275 /* The stack type is a null literal*/
276 NULL_LITERAL_MASK = 0x400,
278 /**Used by ldarg.0 and family to let delegate verification happens.*/
279 THIS_POINTER_MASK = 0x800,
281 /**Signals that this is a boxed value type*/
282 BOXED_MASK = 0x1000,
284 /*This is an unitialized this ref*/
285 UNINIT_THIS_MASK = 0x2000,
288 static const char* const
289 type_names [TYPE_MAX + 1] = {
290 "Invalid",
291 "Int32",
292 "Int64",
293 "Native Int",
294 "Float64",
295 "Native Pointer",
296 "Complex"
299 enum {
300 PREFIX_UNALIGNED = 1,
301 PREFIX_VOLATILE = 2,
302 PREFIX_TAIL = 4,
303 PREFIX_CONSTRAINED = 8,
304 PREFIX_READONLY = 16
306 //////////////////////////////////////////////////////////////////
308 #ifdef ENABLE_VERIFIER_STATS
310 #define _MEM_ALLOC(amt) do { allocated_memory += (amt); working_set += (amt); } while (0)
311 #define _MEM_FREE(amt) do { working_set -= (amt); } while (0)
313 static int allocated_memory;
314 static int working_set;
315 static int max_allocated_memory;
316 static int max_working_set;
317 static int total_allocated_memory;
319 static void
320 finish_collect_stats (void)
322 max_allocated_memory = MAX (max_allocated_memory, allocated_memory);
323 max_working_set = MAX (max_working_set, working_set);
324 total_allocated_memory += allocated_memory;
325 allocated_memory = working_set = 0;
328 static void
329 init_verifier_stats (void)
331 static gboolean inited;
332 if (!inited) {
333 inited = TRUE;
334 mono_counters_register ("Maximum memory allocated during verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &max_allocated_memory);
335 mono_counters_register ("Maximum memory used during verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &max_working_set);
336 mono_counters_register ("Total memory allocated for verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &total_allocated_memory);
340 #else
342 #define _MEM_ALLOC(amt) do {} while (0)
343 #define _MEM_FREE(amt) do { } while (0)
345 #define finish_collect_stats()
346 #define init_verifier_stats()
348 #endif
351 //////////////////////////////////////////////////////////////////
354 /*Token validation macros and functions */
355 #define IS_MEMBER_REF(token) (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
356 #define IS_METHOD_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
357 #define IS_METHOD_SPEC(token) (mono_metadata_token_table (token) == MONO_TABLE_METHODSPEC)
358 #define IS_FIELD_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_FIELD)
360 #define IS_TYPE_REF(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPEREF)
361 #define IS_TYPE_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPEDEF)
362 #define IS_TYPE_SPEC(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC)
363 #define IS_METHOD_DEF_OR_REF_OR_SPEC(token) (IS_METHOD_DEF (token) || IS_MEMBER_REF (token) || IS_METHOD_SPEC (token))
364 #define IS_TYPE_DEF_OR_REF_OR_SPEC(token) (IS_TYPE_DEF (token) || IS_TYPE_REF (token) || IS_TYPE_SPEC (token))
365 #define IS_FIELD_DEF_OR_REF(token) (IS_FIELD_DEF (token) || IS_MEMBER_REF (token))
368 * Verify if @token refers to a valid row on int's table.
370 static gboolean
371 token_bounds_check (MonoImage *image, guint32 token)
373 if (image_is_dynamic (image))
374 return mono_dynamic_image_is_valid_token ((MonoDynamicImage*)image, token);
375 return image->tables [mono_metadata_token_table (token)].rows >= mono_metadata_token_index (token) && mono_metadata_token_index (token) > 0;
378 static MonoType *
379 mono_type_create_fnptr_from_mono_method (VerifyContext *ctx, MonoMethod *method)
381 MonoType *res = g_new0 (MonoType, 1);
382 _MEM_ALLOC (sizeof (MonoType));
384 //FIXME use mono_method_get_signature_full
385 res->data.method = mono_method_signature (method);
386 res->type = MONO_TYPE_FNPTR;
387 ctx->funptrs = g_slist_prepend (ctx->funptrs, res);
388 return res;
392 * mono_type_is_enum_type:
394 * Returns: TRUE if @type is an enum type.
396 static gboolean
397 mono_type_is_enum_type (MonoType *type)
399 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)
400 return TRUE;
401 if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype)
402 return TRUE;
403 return FALSE;
407 * mono_type_is_value_type:
409 * Returns: TRUE if @type is named after @namespace.@name.
412 static gboolean
413 mono_type_is_value_type (MonoType *type, const char *namespace_, const char *name)
415 return type->type == MONO_TYPE_VALUETYPE &&
416 !strcmp (namespace_, type->data.klass->name_space) &&
417 !strcmp (name, type->data.klass->name);
421 * Returns TURE if @type is VAR or MVAR
423 static gboolean
424 mono_type_is_generic_argument (MonoType *type)
426 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
430 * mono_type_get_underlying_type_any:
432 * This functions is just like mono_type_get_underlying_type but it doesn't care if the type is byref.
434 * Returns the underlying type of @type regardless if it is byref or not.
436 static MonoType*
437 mono_type_get_underlying_type_any (MonoType *type)
439 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)
440 return mono_class_enum_basetype (type->data.klass);
441 if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype)
442 return mono_class_enum_basetype (type->data.generic_class->container_class);
443 return type;
446 static G_GNUC_UNUSED const char*
447 mono_type_get_stack_name (MonoType *type)
449 return type_names [get_stack_type (type) & TYPE_MASK];
452 #define CTOR_REQUIRED_FLAGS (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_RT_SPECIAL_NAME)
453 #define CTOR_INVALID_FLAGS (METHOD_ATTRIBUTE_STATIC)
455 static gboolean
456 mono_method_is_constructor (MonoMethod *method)
458 return ((method->flags & CTOR_REQUIRED_FLAGS) == CTOR_REQUIRED_FLAGS &&
459 !(method->flags & CTOR_INVALID_FLAGS) &&
460 !strcmp (".ctor", method->name));
463 static gboolean
464 mono_class_has_default_constructor (MonoClass *klass)
466 MonoMethod *method;
467 int i;
469 mono_class_setup_methods (klass);
470 if (mono_class_has_failure (klass))
471 return FALSE;
473 int mcount = mono_class_get_method_count (klass);
474 for (i = 0; i < mcount; ++i) {
475 method = klass->methods [i];
476 if (mono_method_is_constructor (method) &&
477 mono_method_signature (method) &&
478 mono_method_signature (method)->param_count == 0 &&
479 (method->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC)
480 return TRUE;
482 return FALSE;
486 * Verify if @type is valid for the given @ctx verification context.
487 * this function checks for VAR and MVAR types that are invalid under the current verifier,
489 static gboolean
490 mono_type_is_valid_type_in_context_full (MonoType *type, MonoGenericContext *context, gboolean check_gtd)
492 int i;
493 MonoGenericInst *inst;
495 switch (type->type) {
496 case MONO_TYPE_VAR:
497 case MONO_TYPE_MVAR:
498 if (!context)
499 return FALSE;
500 inst = type->type == MONO_TYPE_VAR ? context->class_inst : context->method_inst;
501 if (!inst || mono_type_get_generic_param_num (type) >= inst->type_argc)
502 return FALSE;
503 break;
504 case MONO_TYPE_SZARRAY:
505 return mono_type_is_valid_type_in_context_full (&type->data.klass->byval_arg, context, check_gtd);
506 case MONO_TYPE_ARRAY:
507 return mono_type_is_valid_type_in_context_full (&type->data.array->eklass->byval_arg, context, check_gtd);
508 case MONO_TYPE_PTR:
509 return mono_type_is_valid_type_in_context_full (type->data.type, context, check_gtd);
510 case MONO_TYPE_GENERICINST:
511 inst = type->data.generic_class->context.class_inst;
512 if (!inst->is_open)
513 break;
514 for (i = 0; i < inst->type_argc; ++i)
515 if (!mono_type_is_valid_type_in_context_full (inst->type_argv [i], context, check_gtd))
516 return FALSE;
517 break;
518 case MONO_TYPE_CLASS:
519 case MONO_TYPE_VALUETYPE: {
520 MonoClass *klass = type->data.klass;
522 * It's possible to encode generic'sh types in such a way that they disguise themselves as class or valuetype.
523 * Fixing the type decoding is really tricky since under some cases this behavior is needed, for example, to
524 * have a 'class' type pointing to a 'genericinst' class.
526 * For the runtime these non canonical (weird) encodings work fine, the worst they can cause is some
527 * reflection oddities which are harmless - to security at least.
529 if (klass->byval_arg.type != type->type)
530 return mono_type_is_valid_type_in_context_full (&klass->byval_arg, context, check_gtd);
532 if (check_gtd && mono_class_is_gtd (klass))
533 return FALSE;
534 break;
536 default:
537 break;
539 return TRUE;
542 static gboolean
543 mono_type_is_valid_type_in_context (MonoType *type, MonoGenericContext *context)
545 return mono_type_is_valid_type_in_context_full (type, context, FALSE);
548 /*This function returns NULL if the type is not instantiatable*/
549 static MonoType*
550 verifier_inflate_type (VerifyContext *ctx, MonoType *type, MonoGenericContext *context)
552 MonoError error;
553 MonoType *result;
555 result = mono_class_inflate_generic_type_checked (type, context, &error);
556 if (!mono_error_ok (&error)) {
557 mono_error_cleanup (&error);
558 return NULL;
560 return result;
563 /*A side note here. We don't need to check if arguments are broken since this
564 is only need to be done by the runtime before realizing the type.
566 static gboolean
567 is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
569 MonoError error;
570 int i;
572 if (ginst->type_argc != gc->type_argc)
573 return FALSE;
575 for (i = 0; i < gc->type_argc; ++i) {
576 MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
577 MonoClass *paramClass;
578 MonoClass **constraints;
579 MonoType *param_type = ginst->type_argv [i];
581 /*it's not our job to validate type variables*/
582 if (mono_type_is_generic_argument (param_type))
583 continue;
585 paramClass = mono_class_from_mono_type (param_type);
588 /* A GTD can't be a generic argument.
590 * Due to how types are encoded we must check for the case of a genericinst MonoType and GTD MonoClass.
591 * This happens in cases such as: class Foo<T> { void X() { new Bar<T> (); } }
593 * Open instantiations can have GTDs as this happens when one type is instantiated with others params
594 * and the former has an expansion into the later. For example:
595 * class B<K> {}
596 * class A<T>: B<K> {}
597 * The type A <K> has a parent B<K>, that is inflated into the GTD B<>.
598 * Since A<K> is open, thus not instantiatable, this is valid.
600 if (mono_class_is_gtd (paramClass) && param_type->type != MONO_TYPE_GENERICINST && !ginst->is_open)
601 return FALSE;
603 /*it's not safe to call mono_class_init from here*/
604 if (mono_class_is_ginst (paramClass) && !paramClass->inited) {
605 if (!mono_class_is_valid_generic_instantiation (NULL, paramClass))
606 return FALSE;
609 if (!param_info->constraints && !(param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK))
610 continue;
612 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && (!paramClass->valuetype || mono_class_is_nullable (paramClass)))
613 return FALSE;
615 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && paramClass->valuetype)
616 return FALSE;
618 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !paramClass->valuetype && !mono_class_has_default_constructor (paramClass))
619 return FALSE;
621 if (!param_info->constraints)
622 continue;
624 for (constraints = param_info->constraints; *constraints; ++constraints) {
625 MonoClass *ctr = *constraints;
626 MonoType *inflated;
628 inflated = mono_class_inflate_generic_type_checked (&ctr->byval_arg, context, &error);
629 if (!mono_error_ok (&error)) {
630 mono_error_cleanup (&error);
631 return FALSE;
633 ctr = mono_class_from_mono_type (inflated);
634 mono_metadata_free_type (inflated);
636 /*FIXME maybe we need the same this as verifier_class_is_assignable_from*/
637 if (!mono_class_is_assignable_from_slow (ctr, paramClass))
638 return FALSE;
641 return TRUE;
645 * mono_generic_param_is_constraint_compatible:
647 * Returns: TRUE if @candidate is constraint compatible with @target.
649 * This means that @candidate constraints are a super set of @target constaints
651 static gboolean
652 mono_generic_param_is_constraint_compatible (VerifyContext *ctx, MonoGenericParam *target, MonoGenericParam *candidate, MonoClass *candidate_param_class, MonoGenericContext *context)
654 MonoGenericParamInfo *tinfo = mono_generic_param_info (target);
655 MonoGenericParamInfo *cinfo = mono_generic_param_info (candidate);
656 MonoClass **candidate_class;
657 gboolean class_constraint_satisfied = FALSE;
658 gboolean valuetype_constraint_satisfied = FALSE;
660 int tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
661 int cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
663 if (cinfo->constraints) {
664 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
665 MonoClass *cc;
666 MonoType *inflated = verifier_inflate_type (ctx, &(*candidate_class)->byval_arg, ctx->generic_context);
667 if (!inflated)
668 return FALSE;
669 cc = mono_class_from_mono_type (inflated);
670 mono_metadata_free_type (inflated);
672 if (mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
673 class_constraint_satisfied = TRUE;
674 else if (!mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
675 valuetype_constraint_satisfied = TRUE;
678 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
679 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
681 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
682 return FALSE;
683 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
684 return FALSE;
685 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
686 valuetype_constraint_satisfied)) {
687 return FALSE;
691 if (tinfo->constraints) {
692 MonoClass **target_class;
693 for (target_class = tinfo->constraints; *target_class; ++target_class) {
694 MonoClass *tc;
695 MonoType *inflated = verifier_inflate_type (ctx, &(*target_class)->byval_arg, context);
696 if (!inflated)
697 return FALSE;
698 tc = mono_class_from_mono_type (inflated);
699 mono_metadata_free_type (inflated);
702 * A constraint from @target might inflate into @candidate itself and in that case we don't need
703 * check it's constraints since it satisfy the constraint by itself.
705 if (mono_metadata_type_equal (&tc->byval_arg, &candidate_param_class->byval_arg))
706 continue;
708 if (!cinfo->constraints)
709 return FALSE;
711 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
712 MonoClass *cc;
713 inflated = verifier_inflate_type (ctx, &(*candidate_class)->byval_arg, ctx->generic_context);
714 if (!inflated)
715 return FALSE;
716 cc = mono_class_from_mono_type (inflated);
717 mono_metadata_free_type (inflated);
719 if (verifier_class_is_assignable_from (tc, cc))
720 break;
723 * This happens when we have the following:
725 * Bar<K> where K : IFace
726 * Foo<T, U> where T : U where U : IFace
727 * ...
728 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
731 if (mono_type_is_generic_argument (&cc->byval_arg)) {
732 MonoGenericParam *other_candidate = verifier_get_generic_param_from_type (ctx, &cc->byval_arg);
734 if (mono_generic_param_is_constraint_compatible (ctx, target, other_candidate, cc, context)) {
735 break;
739 if (!*candidate_class)
740 return FALSE;
743 return TRUE;
746 static MonoGenericParam*
747 verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type)
749 MonoGenericContainer *gc;
750 MonoMethod *method = ctx->method;
751 int num;
753 num = mono_type_get_generic_param_num (type);
755 if (type->type == MONO_TYPE_VAR) {
756 MonoClass *gtd = method->klass;
757 if (mono_class_is_ginst (gtd))
758 gtd = mono_class_get_generic_class (gtd)->container_class;
759 gc = mono_class_try_get_generic_container (gtd);
760 } else { //MVAR
761 MonoMethod *gmd = method;
762 if (method->is_inflated)
763 gmd = ((MonoMethodInflated*)method)->declaring;
764 gc = mono_method_get_generic_container (gmd);
766 if (!gc)
767 return NULL;
768 return mono_generic_container_get_param (gc, num);
774 * Verify if @type is valid for the given @ctx verification context.
775 * this function checks for VAR and MVAR types that are invalid under the current verifier,
776 * This means that it either
778 static gboolean
779 is_valid_type_in_context (VerifyContext *ctx, MonoType *type)
781 return mono_type_is_valid_type_in_context (type, ctx->generic_context);
784 static gboolean
785 is_valid_generic_instantiation_in_context (VerifyContext *ctx, MonoGenericInst *ginst, gboolean check_gtd)
787 int i;
788 for (i = 0; i < ginst->type_argc; ++i) {
789 MonoType *type = ginst->type_argv [i];
791 if (!mono_type_is_valid_type_in_context_full (type, ctx->generic_context, TRUE))
792 return FALSE;
794 return TRUE;
797 static gboolean
798 generic_arguments_respect_constraints (VerifyContext *ctx, MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
800 int i;
801 for (i = 0; i < ginst->type_argc; ++i) {
802 MonoType *type = ginst->type_argv [i];
803 MonoGenericParam *target = mono_generic_container_get_param (gc, i);
804 MonoGenericParam *candidate;
805 MonoClass *candidate_class;
807 if (!mono_type_is_generic_argument (type))
808 continue;
810 if (!is_valid_type_in_context (ctx, type))
811 return FALSE;
813 candidate = verifier_get_generic_param_from_type (ctx, type);
814 candidate_class = mono_class_from_mono_type (type);
816 if (!mono_generic_param_is_constraint_compatible (ctx, target, candidate, candidate_class, context))
817 return FALSE;
819 return TRUE;
822 static gboolean
823 mono_method_repect_method_constraints (VerifyContext *ctx, MonoMethod *method)
825 MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
826 MonoGenericInst *ginst = gmethod->context.method_inst;
827 MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
828 return !gc || generic_arguments_respect_constraints (ctx, gc, &gmethod->context, ginst);
831 static gboolean
832 mono_class_repect_method_constraints (VerifyContext *ctx, MonoClass *klass)
834 MonoGenericClass *gklass = mono_class_get_generic_class (klass);
835 MonoGenericInst *ginst = gklass->context.class_inst;
836 MonoGenericContainer *gc = mono_class_get_generic_container (gklass->container_class);
837 return !gc || generic_arguments_respect_constraints (ctx, gc, &gklass->context, ginst);
840 static gboolean
841 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method)
843 MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
844 MonoGenericInst *ginst = gmethod->context.method_inst;
845 MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
846 if (!gc) /*non-generic inflated method - it's part of a generic type */
847 return TRUE;
848 if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst, TRUE))
849 return FALSE;
850 return is_valid_generic_instantiation (gc, &gmethod->context, ginst);
854 static gboolean
855 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass)
857 MonoGenericClass *gklass = mono_class_get_generic_class (klass);
858 MonoGenericInst *ginst = gklass->context.class_inst;
859 MonoGenericContainer *gc = mono_class_get_generic_container (gklass->container_class);
860 if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst, TRUE))
861 return FALSE;
862 return is_valid_generic_instantiation (gc, &gklass->context, ginst);
865 static gboolean
866 mono_type_is_valid_in_context (VerifyContext *ctx, MonoType *type)
868 MonoClass *klass;
870 if (type == NULL) {
871 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid null type at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
872 return FALSE;
875 if (!is_valid_type_in_context (ctx, type)) {
876 char *str = mono_type_full_name (type);
877 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type (%s%s) (argument out of range or %s is not generic) at 0x%04x",
878 str [0] == '!' ? "" : type->type == MONO_TYPE_VAR ? "!" : "!!",
879 str,
880 type->type == MONO_TYPE_VAR ? "class" : "method",
881 ctx->ip_offset),
882 MONO_EXCEPTION_BAD_IMAGE);
883 g_free (str);
884 return FALSE;
887 klass = mono_class_from_mono_type (type);
888 mono_class_init (klass);
889 if (mono_class_has_failure (klass)) {
890 if (mono_class_is_ginst (klass) && !mono_class_is_valid_generic_instantiation (NULL, klass))
891 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);
892 else
893 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Could not load type %s.%s at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
894 return FALSE;
897 if (mono_class_is_ginst (klass) && mono_class_has_failure (mono_class_get_generic_class (klass)->container_class)) {
898 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);
899 return FALSE;
902 if (!mono_class_is_ginst (klass))
903 return TRUE;
905 if (!mono_class_is_valid_generic_instantiation (ctx, klass)) {
906 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);
907 return FALSE;
910 if (!mono_class_repect_method_constraints (ctx, klass)) {
911 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);
912 return FALSE;
915 return TRUE;
918 static verify_result_t
919 mono_method_is_valid_in_context (VerifyContext *ctx, MonoMethod *method)
921 if (!mono_type_is_valid_in_context (ctx, &method->klass->byval_arg))
922 return RESULT_INVALID;
924 if (!method->is_inflated)
925 return RESULT_VALID;
927 if (!mono_method_is_valid_generic_instantiation (ctx, method)) {
928 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);
929 return RESULT_INVALID;
932 if (!mono_method_repect_method_constraints (ctx, method)) {
933 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));
934 return RESULT_UNVERIFIABLE;
936 return RESULT_VALID;
940 static MonoClassField*
941 verifier_load_field (VerifyContext *ctx, int token, MonoClass **out_klass, const char *opcode) {
942 MonoError error;
943 MonoClassField *field;
944 MonoClass *klass = NULL;
946 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
947 field = (MonoClassField *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
948 klass = field ? field->parent : NULL;
949 } else {
950 if (!IS_FIELD_DEF_OR_REF (token) || !token_bounds_check (ctx->image, token)) {
951 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);
952 return NULL;
955 field = mono_field_from_token_checked (ctx->image, token, &klass, ctx->generic_context, &error);
956 mono_error_cleanup (&error); /*FIXME don't swallow the error */
959 if (!field || !field->parent || !klass) {
960 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);
961 return NULL;
964 if (!mono_type_is_valid_in_context (ctx, &klass->byval_arg))
965 return NULL;
967 if (mono_field_get_flags (field) & FIELD_ATTRIBUTE_LITERAL) {
968 char *type_name = mono_type_get_full_name (field->parent);
969 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot reference literal field %s::%s at 0x%04x", type_name, field->name, ctx->ip_offset));
970 g_free (type_name);
971 return NULL;
974 *out_klass = klass;
975 return field;
978 static MonoMethod*
979 verifier_load_method (VerifyContext *ctx, int token, const char *opcode) {
980 MonoMethod* method;
983 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
984 method = (MonoMethod *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
985 } else {
986 MonoError error;
987 if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
988 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);
989 return NULL;
992 method = mono_get_method_checked (ctx->image, token, NULL, ctx->generic_context, &error);
993 mono_error_cleanup (&error); /* FIXME don't swallow this error */
996 if (!method) {
997 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);
998 return NULL;
1001 if (mono_method_is_valid_in_context (ctx, method) == RESULT_INVALID)
1002 return NULL;
1004 return method;
1007 static MonoType*
1008 verifier_load_type (VerifyContext *ctx, int token, const char *opcode) {
1009 MonoType* type;
1011 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
1012 MonoClass *klass = (MonoClass *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
1013 type = klass ? &klass->byval_arg : NULL;
1014 } else {
1015 MonoError error;
1016 if (!IS_TYPE_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
1017 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid type token 0x%08x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
1018 return NULL;
1020 type = mono_type_get_checked (ctx->image, token, ctx->generic_context, &error);
1021 mono_error_cleanup (&error); /*FIXME don't swallow the error */
1024 if (!type) {
1025 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);
1026 return NULL;
1029 if (!mono_type_is_valid_in_context (ctx, type))
1030 return NULL;
1032 return type;
1036 /* stack_slot_get_type:
1038 * Returns the stack type of @value. This value includes POINTER_MASK.
1040 * Use this function to checks that account for a managed pointer.
1042 static gint32
1043 stack_slot_get_type (ILStackDesc *value)
1045 return value->stype & RAW_TYPE_MASK;
1048 /* stack_slot_get_underlying_type:
1050 * Returns the stack type of @value. This value does not include POINTER_MASK.
1052 * Use this function is cases where the fact that the value could be a managed pointer is
1053 * irrelevant. For example, field load doesn't care about this fact of type on stack.
1055 static gint32
1056 stack_slot_get_underlying_type (ILStackDesc *value)
1058 return value->stype & TYPE_MASK;
1061 /* stack_slot_is_managed_pointer:
1063 * Returns TRUE is @value is a managed pointer.
1065 static gboolean
1066 stack_slot_is_managed_pointer (ILStackDesc *value)
1068 return (value->stype & POINTER_MASK) == POINTER_MASK;
1071 /* stack_slot_is_managed_mutability_pointer:
1073 * Returns TRUE is @value is a managed mutability pointer.
1075 static G_GNUC_UNUSED gboolean
1076 stack_slot_is_managed_mutability_pointer (ILStackDesc *value)
1078 return (value->stype & CMMP_MASK) == CMMP_MASK;
1081 /* stack_slot_is_null_literal:
1083 * Returns TRUE is @value is the null literal.
1085 static gboolean
1086 stack_slot_is_null_literal (ILStackDesc *value)
1088 return (value->stype & NULL_LITERAL_MASK) == NULL_LITERAL_MASK;
1092 /* stack_slot_is_this_pointer:
1094 * Returns TRUE is @value is the this literal
1096 static gboolean
1097 stack_slot_is_this_pointer (ILStackDesc *value)
1099 return (value->stype & THIS_POINTER_MASK) == THIS_POINTER_MASK;
1102 /* stack_slot_is_boxed_value:
1104 * Returns TRUE is @value is a boxed value
1106 static gboolean
1107 stack_slot_is_boxed_value (ILStackDesc *value)
1109 return (value->stype & BOXED_MASK) == BOXED_MASK;
1112 static const char *
1113 stack_slot_get_name (ILStackDesc *value)
1115 return type_names [value->stype & TYPE_MASK];
1118 #define APPEND_WITH_PREDICATE(PRED,NAME) do {\
1119 if (PRED (value)) { \
1120 if (!first) \
1121 g_string_append (str, ", "); \
1122 g_string_append (str, NAME); \
1123 first = FALSE; \
1124 } } while (0)
1126 static char*
1127 stack_slot_stack_type_full_name (ILStackDesc *value)
1129 GString *str = g_string_new ("");
1130 char *result;
1131 gboolean has_pred = FALSE, first = TRUE;
1133 if ((value->stype & TYPE_MASK) != value->stype) {
1134 g_string_append(str, "[");
1135 APPEND_WITH_PREDICATE (stack_slot_is_this_pointer, "this");
1136 APPEND_WITH_PREDICATE (stack_slot_is_boxed_value, "boxed");
1137 APPEND_WITH_PREDICATE (stack_slot_is_null_literal, "null");
1138 APPEND_WITH_PREDICATE (stack_slot_is_managed_mutability_pointer, "cmmp");
1139 APPEND_WITH_PREDICATE (stack_slot_is_managed_pointer, "mp");
1140 has_pred = TRUE;
1143 if (mono_type_is_generic_argument (value->type) && !stack_slot_is_boxed_value (value)) {
1144 if (!has_pred)
1145 g_string_append(str, "[");
1146 if (!first)
1147 g_string_append (str, ", ");
1148 g_string_append (str, "unboxed");
1149 has_pred = TRUE;
1152 if (has_pred)
1153 g_string_append(str, "] ");
1155 g_string_append (str, stack_slot_get_name (value));
1156 result = str->str;
1157 g_string_free (str, FALSE);
1158 return result;
1161 static char*
1162 stack_slot_full_name (ILStackDesc *value)
1164 char *type_name = mono_type_full_name (value->type);
1165 char *stack_name = stack_slot_stack_type_full_name (value);
1166 char *res = g_strdup_printf ("%s (%s)", type_name, stack_name);
1167 g_free (type_name);
1168 g_free (stack_name);
1169 return res;
1172 //////////////////////////////////////////////////////////////////
1173 void
1174 mono_free_verify_list (GSList *list)
1176 MonoVerifyInfoExtended *info;
1177 GSList *tmp;
1179 for (tmp = list; tmp; tmp = tmp->next) {
1180 info = (MonoVerifyInfoExtended *)tmp->data;
1181 g_free (info->info.message);
1182 g_free (info);
1184 g_slist_free (list);
1187 #define ADD_ERROR(list,msg) \
1188 do { \
1189 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1190 vinfo->info.status = MONO_VERIFY_ERROR; \
1191 vinfo->info.message = (msg); \
1192 (list) = g_slist_prepend ((list), vinfo); \
1193 } while (0)
1195 #define ADD_WARN(list,code,msg) \
1196 do { \
1197 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1198 vinfo->info.status = (code); \
1199 vinfo->info.message = (msg); \
1200 (list) = g_slist_prepend ((list), vinfo); \
1201 } while (0)
1203 #define ADD_INVALID(list,msg) \
1204 do { \
1205 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1206 vinfo->status = MONO_VERIFY_ERROR; \
1207 vinfo->message = (msg); \
1208 (list) = g_slist_prepend ((list), vinfo); \
1209 /*G_BREAKPOINT ();*/ \
1210 goto invalid_cil; \
1211 } while (0)
1213 #define CHECK_STACK_UNDERFLOW(num) \
1214 do { \
1215 if (cur_stack < (num)) \
1216 ADD_INVALID (list, g_strdup_printf ("Stack underflow at 0x%04x (%d items instead of %d)", ip_offset, cur_stack, (num))); \
1217 } while (0)
1219 #define CHECK_STACK_OVERFLOW() \
1220 do { \
1221 if (cur_stack >= max_stack) \
1222 ADD_INVALID (list, g_strdup_printf ("Maxstack exceeded at 0x%04x", ip_offset)); \
1223 } while (0)
1226 static int
1227 in_any_block (MonoMethodHeader *header, guint offset)
1229 int i;
1230 MonoExceptionClause *clause;
1232 for (i = 0; i < header->num_clauses; ++i) {
1233 clause = &header->clauses [i];
1234 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1235 return 1;
1236 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1237 return 1;
1238 if (MONO_OFFSET_IN_FILTER (clause, offset))
1239 return 1;
1241 return 0;
1245 * in_any_exception_block:
1247 * Returns TRUE is @offset is part of any exception clause (filter, handler, catch, finally or fault).
1249 static gboolean
1250 in_any_exception_block (MonoMethodHeader *header, guint offset)
1252 int i;
1253 MonoExceptionClause *clause;
1255 for (i = 0; i < header->num_clauses; ++i) {
1256 clause = &header->clauses [i];
1257 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1258 return TRUE;
1259 if (MONO_OFFSET_IN_FILTER (clause, offset))
1260 return TRUE;
1262 return FALSE;
1266 * is_valid_branch_instruction:
1268 * Verify if it's valid to perform a branch from @offset to @target.
1269 * This should be used with br and brtrue/false.
1270 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1271 * The major difference from other similiar functions is that branching into a
1272 * finally/fault block is invalid instead of just unverifiable.
1274 static int
1275 is_valid_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1277 int i;
1278 MonoExceptionClause *clause;
1280 for (i = 0; i < header->num_clauses; ++i) {
1281 clause = &header->clauses [i];
1282 /*branching into a finally block is invalid*/
1283 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) &&
1284 !MONO_OFFSET_IN_HANDLER (clause, offset) &&
1285 MONO_OFFSET_IN_HANDLER (clause, target))
1286 return 2;
1288 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1289 return 1;
1290 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1291 return 1;
1292 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1293 return 1;
1295 return 0;
1299 * is_valid_cmp_branch_instruction:
1301 * Verify if it's valid to perform a branch from @offset to @target.
1302 * This should be used with binary comparison branching instruction, like beq, bge and similars.
1303 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1305 * The major differences from other similar functions are that most errors lead to invalid
1306 * code and only branching out of finally, filter or fault clauses is unverifiable.
1308 static int
1309 is_valid_cmp_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1311 int i;
1312 MonoExceptionClause *clause;
1314 for (i = 0; i < header->num_clauses; ++i) {
1315 clause = &header->clauses [i];
1316 /*branching out of a handler or finally*/
1317 if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE &&
1318 MONO_OFFSET_IN_HANDLER (clause, offset) &&
1319 !MONO_OFFSET_IN_HANDLER (clause, target))
1320 return 1;
1322 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1323 return 2;
1324 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1325 return 2;
1326 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1327 return 2;
1329 return 0;
1333 * A leave can't escape a finally block
1335 static int
1336 is_correct_leave (MonoMethodHeader *header, guint offset, guint target)
1338 int i;
1339 MonoExceptionClause *clause;
1341 for (i = 0; i < header->num_clauses; ++i) {
1342 clause = &header->clauses [i];
1343 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY && MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
1344 return 0;
1345 if (MONO_OFFSET_IN_FILTER (clause, offset))
1346 return 0;
1348 return 1;
1352 * A rethrow can't happen outside of a catch handler.
1354 static int
1355 is_correct_rethrow (MonoMethodHeader *header, guint offset)
1357 int i;
1358 MonoExceptionClause *clause;
1360 for (i = 0; i < header->num_clauses; ++i) {
1361 clause = &header->clauses [i];
1362 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1363 return 1;
1365 return 0;
1369 * An endfinally can't happen outside of a finally/fault handler.
1371 static int
1372 is_correct_endfinally (MonoMethodHeader *header, guint offset)
1374 int i;
1375 MonoExceptionClause *clause;
1377 for (i = 0; i < header->num_clauses; ++i) {
1378 clause = &header->clauses [i];
1379 if (MONO_OFFSET_IN_HANDLER (clause, offset) && (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY))
1380 return 1;
1382 return 0;
1387 * An endfilter can only happens inside a filter clause.
1388 * In non-strict mode filter is allowed inside the handler clause too
1390 static MonoExceptionClause *
1391 is_correct_endfilter (VerifyContext *ctx, guint offset)
1393 int i;
1394 MonoExceptionClause *clause;
1396 for (i = 0; i < ctx->header->num_clauses; ++i) {
1397 clause = &ctx->header->clauses [i];
1398 if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER)
1399 continue;
1400 if (MONO_OFFSET_IN_FILTER (clause, offset))
1401 return clause;
1402 if (!IS_STRICT_MODE (ctx) && MONO_OFFSET_IN_HANDLER (clause, offset))
1403 return clause;
1405 return NULL;
1410 * Non-strict endfilter can happens inside a try block or any handler block
1412 static int
1413 is_unverifiable_endfilter (VerifyContext *ctx, guint offset)
1415 int i;
1416 MonoExceptionClause *clause;
1418 for (i = 0; i < ctx->header->num_clauses; ++i) {
1419 clause = &ctx->header->clauses [i];
1420 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1421 return 1;
1423 return 0;
1426 static gboolean
1427 is_valid_bool_arg (ILStackDesc *arg)
1429 if (stack_slot_is_managed_pointer (arg) || stack_slot_is_boxed_value (arg) || stack_slot_is_null_literal (arg))
1430 return TRUE;
1433 switch (stack_slot_get_underlying_type (arg)) {
1434 case TYPE_I4:
1435 case TYPE_I8:
1436 case TYPE_NATIVE_INT:
1437 case TYPE_PTR:
1438 return TRUE;
1439 case TYPE_COMPLEX:
1440 g_assert (arg->type);
1441 switch (arg->type->type) {
1442 case MONO_TYPE_CLASS:
1443 case MONO_TYPE_STRING:
1444 case MONO_TYPE_OBJECT:
1445 case MONO_TYPE_SZARRAY:
1446 case MONO_TYPE_ARRAY:
1447 case MONO_TYPE_FNPTR:
1448 case MONO_TYPE_PTR:
1449 return TRUE;
1450 case MONO_TYPE_GENERICINST:
1451 /*We need to check if the container class
1452 * of the generic type is a valuetype, iow:
1453 * is it a "class Foo<T>" or a "struct Foo<T>"?
1455 return !arg->type->data.generic_class->container_class->valuetype;
1456 default:
1457 return FALSE;
1459 default:
1460 return FALSE;
1465 /*Type manipulation helper*/
1467 /*Returns the byref version of the supplied MonoType*/
1468 static MonoType*
1469 mono_type_get_type_byref (MonoType *type)
1471 if (type->byref)
1472 return type;
1473 return &mono_class_from_mono_type (type)->this_arg;
1477 /*Returns the byval version of the supplied MonoType*/
1478 static MonoType*
1479 mono_type_get_type_byval (MonoType *type)
1481 if (!type->byref)
1482 return type;
1483 return &mono_class_from_mono_type (type)->byval_arg;
1486 static MonoType*
1487 mono_type_from_stack_slot (ILStackDesc *slot)
1489 if (stack_slot_is_managed_pointer (slot))
1490 return mono_type_get_type_byref (slot->type);
1491 return slot->type;
1494 /*Stack manipulation code*/
1496 static void
1497 ensure_stack_size (ILCodeDesc *stack, int required)
1499 int new_size = 8;
1500 ILStackDesc *tmp;
1502 if (required < stack->max_size)
1503 return;
1505 /* We don't have to worry about the exponential growth since stack_copy prune unused space */
1506 new_size = MAX (8, MAX (required, stack->max_size * 2));
1508 g_assert (new_size >= stack->size);
1509 g_assert (new_size >= required);
1511 tmp = g_new0 (ILStackDesc, new_size);
1512 _MEM_ALLOC (sizeof (ILStackDesc) * new_size);
1514 if (stack->stack) {
1515 if (stack->size)
1516 memcpy (tmp, stack->stack, stack->size * sizeof (ILStackDesc));
1517 g_free (stack->stack);
1518 _MEM_FREE (sizeof (ILStackDesc) * stack->max_size);
1521 stack->stack = tmp;
1522 stack->max_size = new_size;
1525 static void
1526 stack_init (VerifyContext *ctx, ILCodeDesc *state)
1528 if (state->flags & IL_CODE_FLAG_STACK_INITED)
1529 return;
1530 state->size = state->max_size = 0;
1531 state->flags |= IL_CODE_FLAG_STACK_INITED;
1534 static void
1535 stack_copy (ILCodeDesc *to, ILCodeDesc *from)
1537 ensure_stack_size (to, from->size);
1538 to->size = from->size;
1540 /*stack copy happens at merge points, which have small stacks*/
1541 if (from->size)
1542 memcpy (to->stack, from->stack, sizeof (ILStackDesc) * from->size);
1545 static void
1546 copy_stack_value (ILStackDesc *to, ILStackDesc *from)
1548 to->stype = from->stype;
1549 to->type = from->type;
1550 to->method = from->method;
1553 static int
1554 check_underflow (VerifyContext *ctx, int size)
1556 if (ctx->eval.size < size) {
1557 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack underflow, required %d, but have %d at 0x%04x", size, ctx->eval.size, ctx->ip_offset));
1558 return 0;
1560 return 1;
1563 static int
1564 check_overflow (VerifyContext *ctx)
1566 if (ctx->eval.size >= ctx->max_stack) {
1567 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have stack-depth %d at 0x%04x", ctx->eval.size + 1, ctx->ip_offset));
1568 return 0;
1570 return 1;
1573 /*This reject out PTR, FNPTR and TYPEDBYREF*/
1574 static gboolean
1575 check_unmanaged_pointer (VerifyContext *ctx, ILStackDesc *value)
1577 if (stack_slot_get_type (value) == TYPE_PTR) {
1578 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1579 return 0;
1581 return 1;
1584 /*TODO verify if MONO_TYPE_TYPEDBYREF is not allowed here as well.*/
1585 static gboolean
1586 check_unverifiable_type (VerifyContext *ctx, MonoType *type)
1588 if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
1589 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1590 return 0;
1592 return 1;
1595 static ILStackDesc *
1596 stack_push (VerifyContext *ctx)
1598 g_assert (ctx->eval.size < ctx->max_stack);
1599 g_assert (ctx->eval.size <= ctx->eval.max_size);
1601 ensure_stack_size (&ctx->eval, ctx->eval.size + 1);
1603 return & ctx->eval.stack [ctx->eval.size++];
1606 static ILStackDesc *
1607 stack_push_val (VerifyContext *ctx, int stype, MonoType *type)
1609 ILStackDesc *top = stack_push (ctx);
1610 top->stype = stype;
1611 top->type = type;
1612 return top;
1615 static ILStackDesc *
1616 stack_pop (VerifyContext *ctx)
1618 ILStackDesc *ret;
1619 g_assert (ctx->eval.size > 0);
1620 ret = ctx->eval.stack + --ctx->eval.size;
1621 if ((ret->stype & UNINIT_THIS_MASK) == UNINIT_THIS_MASK)
1622 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Found use of uninitialized 'this ptr' ref at 0x%04x", ctx->ip_offset));
1623 return ret;
1626 /* This function allows to safely pop an unititialized this ptr from
1627 * the eval stack without marking the method as unverifiable.
1629 static ILStackDesc *
1630 stack_pop_safe (VerifyContext *ctx)
1632 g_assert (ctx->eval.size > 0);
1633 return ctx->eval.stack + --ctx->eval.size;
1636 /*Positive number distance from stack top. [0] is stack top, [1] is the one below*/
1637 static ILStackDesc*
1638 stack_peek (VerifyContext *ctx, int distance)
1640 g_assert (ctx->eval.size - distance > 0);
1641 return ctx->eval.stack + (ctx->eval.size - 1 - distance);
1644 static ILStackDesc *
1645 stack_push_stack_val (VerifyContext *ctx, ILStackDesc *value)
1647 ILStackDesc *top = stack_push (ctx);
1648 copy_stack_value (top, value);
1649 return top;
1652 /* Returns the MonoType associated with the token, or NULL if it is invalid.
1654 * A boxable type can be either a reference or value type, but cannot be a byref type or an unmanaged pointer
1655 * */
1656 static MonoType*
1657 get_boxable_mono_type (VerifyContext* ctx, int token, const char *opcode)
1659 MonoType *type;
1660 MonoClass *klass;
1662 if (!(type = verifier_load_type (ctx, token, opcode)))
1663 return NULL;
1665 if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
1666 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type for %s at 0x%04x", opcode, ctx->ip_offset));
1667 return NULL;
1670 if (type->type == MONO_TYPE_VOID) {
1671 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type for %s at 0x%04x", opcode, ctx->ip_offset));
1672 return NULL;
1675 if (type->type == MONO_TYPE_TYPEDBYREF)
1676 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid use of typedbyref for %s at 0x%04x", opcode, ctx->ip_offset));
1678 if (!(klass = mono_class_from_mono_type (type)))
1679 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not retrieve type token for %s at 0x%04x", opcode, ctx->ip_offset));
1681 if (mono_class_is_gtd (klass) && type->type != MONO_TYPE_GENERICINST)
1682 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));
1684 check_unverifiable_type (ctx, type);
1685 return type;
1689 /*operation result tables */
1691 static const unsigned char bin_op_table [TYPE_MAX][TYPE_MAX] = {
1692 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1693 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1694 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1695 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1696 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1697 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1700 static const unsigned char add_table [TYPE_MAX][TYPE_MAX] = {
1701 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1702 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1703 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1704 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1705 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1706 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1709 static const unsigned char sub_table [TYPE_MAX][TYPE_MAX] = {
1710 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1711 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1712 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1713 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1714 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1715 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1718 static const unsigned char int_bin_op_table [TYPE_MAX][TYPE_MAX] = {
1719 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1720 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1721 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1722 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1723 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1724 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1727 static const unsigned char shift_op_table [TYPE_MAX][TYPE_MAX] = {
1728 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1729 {TYPE_I8, TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV},
1730 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1731 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1732 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1733 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1736 static const unsigned char cmp_br_op [TYPE_MAX][TYPE_MAX] = {
1737 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1738 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1739 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1740 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1741 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV},
1742 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1745 static const unsigned char cmp_br_eq_op [TYPE_MAX][TYPE_MAX] = {
1746 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1747 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1748 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV},
1749 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1750 {TYPE_INV, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_I4, TYPE_INV},
1751 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4},
1754 static const unsigned char add_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
1755 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1756 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1757 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1758 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1759 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1760 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1763 static const unsigned char sub_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
1764 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1765 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1766 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1767 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1768 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1769 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1772 static const unsigned char bin_ovf_table [TYPE_MAX][TYPE_MAX] = {
1773 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1774 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1775 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1776 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1777 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1778 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1781 #ifdef MONO_VERIFIER_DEBUG
1783 /*debug helpers */
1784 static void
1785 dump_stack_value (ILStackDesc *value)
1787 printf ("[(%x)(%x)", value->type->type, value->stype);
1789 if (stack_slot_is_this_pointer (value))
1790 printf ("[this] ");
1792 if (stack_slot_is_boxed_value (value))
1793 printf ("[boxed] ");
1795 if (stack_slot_is_null_literal (value))
1796 printf ("[null] ");
1798 if (stack_slot_is_managed_mutability_pointer (value))
1799 printf ("Controled Mutability MP: ");
1801 if (stack_slot_is_managed_pointer (value))
1802 printf ("Managed Pointer to: ");
1804 switch (stack_slot_get_underlying_type (value)) {
1805 case TYPE_INV:
1806 printf ("invalid type]");
1807 return;
1808 case TYPE_I4:
1809 printf ("int32]");
1810 return;
1811 case TYPE_I8:
1812 printf ("int64]");
1813 return;
1814 case TYPE_NATIVE_INT:
1815 printf ("native int]");
1816 return;
1817 case TYPE_R8:
1818 printf ("float64]");
1819 return;
1820 case TYPE_PTR:
1821 printf ("unmanaged pointer]");
1822 return;
1823 case TYPE_COMPLEX:
1824 switch (value->type->type) {
1825 case MONO_TYPE_CLASS:
1826 case MONO_TYPE_VALUETYPE:
1827 printf ("complex] (%s)", value->type->data.klass->name);
1828 return;
1829 case MONO_TYPE_STRING:
1830 printf ("complex] (string)");
1831 return;
1832 case MONO_TYPE_OBJECT:
1833 printf ("complex] (object)");
1834 return;
1835 case MONO_TYPE_SZARRAY:
1836 printf ("complex] (%s [])", value->type->data.klass->name);
1837 return;
1838 case MONO_TYPE_ARRAY:
1839 printf ("complex] (%s [%d %d %d])",
1840 value->type->data.array->eklass->name,
1841 value->type->data.array->rank,
1842 value->type->data.array->numsizes,
1843 value->type->data.array->numlobounds);
1844 return;
1845 case MONO_TYPE_GENERICINST:
1846 printf ("complex] (inst of %s )", value->type->data.generic_class->container_class->name);
1847 return;
1848 case MONO_TYPE_VAR:
1849 printf ("complex] (type generic param !%d - %s) ", value->type->data.generic_param->num, mono_generic_param_info (value->type->data.generic_param)->name);
1850 return;
1851 case MONO_TYPE_MVAR:
1852 printf ("complex] (method generic param !!%d - %s) ", value->type->data.generic_param->num, mono_generic_param_info (value->type->data.generic_param)->name);
1853 return;
1854 default: {
1855 //should be a boxed value
1856 char * name = mono_type_full_name (value->type);
1857 printf ("complex] %s", name);
1858 g_free (name);
1859 return;
1862 default:
1863 printf ("unknown stack %x type]\n", value->stype);
1864 g_assert_not_reached ();
1868 static void
1869 dump_stack_state (ILCodeDesc *state)
1871 int i;
1873 printf ("(%d) ", state->size);
1874 for (i = 0; i < state->size; ++i)
1875 dump_stack_value (state->stack + i);
1876 printf ("\n");
1878 #endif
1881 * is_array_type_compatible:
1883 * Returns TRUE if candidate array type can be assigned to target.
1885 * Both parameters MUST be of type MONO_TYPE_ARRAY (target->type == MONO_TYPE_ARRAY)
1887 static gboolean
1888 is_array_type_compatible (MonoType *target, MonoType *candidate)
1890 MonoArrayType *left = target->data.array;
1891 MonoArrayType *right = candidate->data.array;
1893 g_assert (target->type == MONO_TYPE_ARRAY);
1894 g_assert (candidate->type == MONO_TYPE_ARRAY);
1896 if (left->rank != right->rank)
1897 return FALSE;
1899 return verifier_class_is_assignable_from (left->eklass, right->eklass);
1902 static int
1903 get_stack_type (MonoType *type)
1905 int mask = 0;
1906 int type_kind = type->type;
1907 if (type->byref)
1908 mask = POINTER_MASK;
1909 /*TODO handle CMMP_MASK */
1911 handle_enum:
1912 switch (type_kind) {
1913 case MONO_TYPE_I1:
1914 case MONO_TYPE_U1:
1915 case MONO_TYPE_BOOLEAN:
1916 case MONO_TYPE_I2:
1917 case MONO_TYPE_U2:
1918 case MONO_TYPE_CHAR:
1919 case MONO_TYPE_I4:
1920 case MONO_TYPE_U4:
1921 return TYPE_I4 | mask;
1923 case MONO_TYPE_I:
1924 case MONO_TYPE_U:
1925 return TYPE_NATIVE_INT | mask;
1927 /* FIXME: the spec says that you cannot have a pointer to method pointer, do we need to check this here? */
1928 case MONO_TYPE_FNPTR:
1929 case MONO_TYPE_PTR:
1930 case MONO_TYPE_TYPEDBYREF:
1931 return TYPE_PTR | mask;
1933 case MONO_TYPE_VAR:
1934 case MONO_TYPE_MVAR:
1936 case MONO_TYPE_CLASS:
1937 case MONO_TYPE_STRING:
1938 case MONO_TYPE_OBJECT:
1939 case MONO_TYPE_SZARRAY:
1940 case MONO_TYPE_ARRAY:
1941 return TYPE_COMPLEX | mask;
1943 case MONO_TYPE_I8:
1944 case MONO_TYPE_U8:
1945 return TYPE_I8 | mask;
1947 case MONO_TYPE_R4:
1948 case MONO_TYPE_R8:
1949 return TYPE_R8 | mask;
1951 case MONO_TYPE_GENERICINST:
1952 case MONO_TYPE_VALUETYPE:
1953 if (mono_type_is_enum_type (type)) {
1954 type = mono_type_get_underlying_type_any (type);
1955 if (!type)
1956 return FALSE;
1957 type_kind = type->type;
1958 goto handle_enum;
1959 } else {
1960 return TYPE_COMPLEX | mask;
1963 default:
1964 return TYPE_INV;
1968 /* convert MonoType to ILStackDesc format (stype) */
1969 static gboolean
1970 set_stack_value (VerifyContext *ctx, ILStackDesc *stack, MonoType *type, int take_addr)
1972 int mask = 0;
1973 int type_kind = type->type;
1975 if (type->byref || take_addr)
1976 mask = POINTER_MASK;
1977 /* TODO handle CMMP_MASK */
1979 handle_enum:
1980 stack->type = type;
1982 switch (type_kind) {
1983 case MONO_TYPE_I1:
1984 case MONO_TYPE_U1:
1985 case MONO_TYPE_BOOLEAN:
1986 case MONO_TYPE_I2:
1987 case MONO_TYPE_U2:
1988 case MONO_TYPE_CHAR:
1989 case MONO_TYPE_I4:
1990 case MONO_TYPE_U4:
1991 stack->stype = TYPE_I4 | mask;
1992 break;
1993 case MONO_TYPE_I:
1994 case MONO_TYPE_U:
1995 stack->stype = TYPE_NATIVE_INT | mask;
1996 break;
1998 /*FIXME: Do we need to check if it's a pointer to the method pointer? The spec says it' illegal to have that.*/
1999 case MONO_TYPE_FNPTR:
2000 case MONO_TYPE_PTR:
2001 case MONO_TYPE_TYPEDBYREF:
2002 stack->stype = TYPE_PTR | mask;
2003 break;
2005 case MONO_TYPE_CLASS:
2006 case MONO_TYPE_STRING:
2007 case MONO_TYPE_OBJECT:
2008 case MONO_TYPE_SZARRAY:
2009 case MONO_TYPE_ARRAY:
2011 case MONO_TYPE_VAR:
2012 case MONO_TYPE_MVAR:
2013 stack->stype = TYPE_COMPLEX | mask;
2014 break;
2016 case MONO_TYPE_I8:
2017 case MONO_TYPE_U8:
2018 stack->stype = TYPE_I8 | mask;
2019 break;
2020 case MONO_TYPE_R4:
2021 case MONO_TYPE_R8:
2022 stack->stype = TYPE_R8 | mask;
2023 break;
2024 case MONO_TYPE_GENERICINST:
2025 case MONO_TYPE_VALUETYPE:
2026 if (mono_type_is_enum_type (type)) {
2027 MonoType *utype = mono_type_get_underlying_type_any (type);
2028 if (!utype) {
2029 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not resolve underlying type of %x at %d", type->type, ctx->ip_offset));
2030 return FALSE;
2032 type = utype;
2033 type_kind = type->type;
2034 goto handle_enum;
2035 } else {
2036 stack->stype = TYPE_COMPLEX | mask;
2037 break;
2039 default:
2040 VERIFIER_DEBUG ( printf ("unknown type 0x%02x in eval stack type\n", type->type); );
2041 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Illegal value set on stack 0x%02x at %d", type->type, ctx->ip_offset));
2042 return FALSE;
2044 return TRUE;
2048 * init_stack_with_value_at_exception_boundary:
2050 * Initialize the stack and push a given type.
2051 * The instruction is marked as been on the exception boundary.
2053 static void
2054 init_stack_with_value_at_exception_boundary (VerifyContext *ctx, ILCodeDesc *code, MonoClass *klass)
2056 MonoError error;
2057 MonoType *type = mono_class_inflate_generic_type_checked (&klass->byval_arg, ctx->generic_context, &error);
2059 if (!mono_error_ok (&error)) {
2060 char *name = mono_type_get_full_name (klass);
2061 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid class %s used for exception", name));
2062 g_free (name);
2063 mono_error_cleanup (&error);
2064 return;
2067 if (!ctx->max_stack) {
2068 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack overflow at 0x%04x", ctx->ip_offset));
2069 return;
2072 stack_init (ctx, code);
2073 ensure_stack_size (code, 1);
2074 set_stack_value (ctx, code->stack, type, FALSE);
2075 ctx->exception_types = g_slist_prepend (ctx->exception_types, type);
2076 code->size = 1;
2077 code->flags |= IL_CODE_FLAG_WAS_TARGET;
2078 if (mono_type_is_generic_argument (type))
2079 code->stack->stype |= BOXED_MASK;
2081 /* Class lazy loading functions */
2082 static GENERATE_GET_CLASS_WITH_CACHE (ienumerable, "System.Collections.Generic", "IEnumerable`1")
2083 static GENERATE_GET_CLASS_WITH_CACHE (icollection, "System.Collections.Generic", "ICollection`1")
2084 static GENERATE_GET_CLASS_WITH_CACHE (ireadonly_list, "System.Collections.Generic", "IReadOnlyList`1")
2085 static GENERATE_GET_CLASS_WITH_CACHE (ireadonly_collection, "System.Collections.Generic", "IReadOnlyCollection`1")
2088 static MonoClass*
2089 get_ienumerable_class (void)
2091 return mono_class_get_ienumerable_class ();
2094 static MonoClass*
2095 get_icollection_class (void)
2097 return mono_class_get_icollection_class ();
2100 static MonoClass*
2101 get_ireadonlylist_class (void)
2103 return mono_class_get_ireadonly_list_class ();
2106 static MonoClass*
2107 get_ireadonlycollection_class (void)
2109 return mono_class_get_ireadonly_collection_class ();
2112 static MonoClass*
2113 inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
2115 MonoType *args [1];
2116 args [0] = &arg0->byval_arg;
2118 return mono_class_bind_generic_parameters (gtype, 1, args, FALSE);
2121 static gboolean
2122 verifier_inflate_and_check_compat (MonoClass *target, MonoClass *gtd, MonoClass *arg)
2124 MonoClass *tmp;
2125 if (!(tmp = inflate_class_one_arg (gtd, arg)))
2126 return FALSE;
2127 if (mono_class_is_variant_compatible (target, tmp, TRUE))
2128 return TRUE;
2129 return FALSE;
2132 static gboolean
2133 verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate)
2135 MonoClass *iface_gtd;
2137 if (target == candidate)
2138 return TRUE;
2140 if (mono_class_has_variant_generic_params (target)) {
2141 if (MONO_CLASS_IS_INTERFACE (target)) {
2142 if (MONO_CLASS_IS_INTERFACE (candidate) && mono_class_is_variant_compatible (target, candidate, TRUE))
2143 return TRUE;
2145 if (candidate->rank == 1) {
2146 if (verifier_inflate_and_check_compat (target, mono_defaults.generic_ilist_class, candidate->element_class))
2147 return TRUE;
2148 if (verifier_inflate_and_check_compat (target, get_icollection_class (), candidate->element_class))
2149 return TRUE;
2150 if (verifier_inflate_and_check_compat (target, get_ienumerable_class (), candidate->element_class))
2151 return TRUE;
2152 if (verifier_inflate_and_check_compat (target, get_ireadonlylist_class (), candidate->element_class))
2153 return TRUE;
2154 if (verifier_inflate_and_check_compat (target, get_ireadonlycollection_class (), candidate->element_class))
2155 return TRUE;
2156 } else {
2157 MonoError error;
2158 int i;
2159 while (candidate && candidate != mono_defaults.object_class) {
2160 mono_class_setup_interfaces (candidate, &error);
2161 if (!mono_error_ok (&error)) {
2162 mono_error_cleanup (&error);
2163 return FALSE;
2166 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
2167 for (i = 0; i < candidate->interface_offsets_count; ++i) {
2168 MonoClass *iface = candidate->interfaces_packed [i];
2169 if (mono_class_is_variant_compatible (target, iface, TRUE))
2170 return TRUE;
2173 for (i = 0; i < candidate->interface_count; ++i) {
2174 MonoClass *iface = candidate->interfaces [i];
2175 if (mono_class_is_variant_compatible (target, iface, TRUE))
2176 return TRUE;
2178 candidate = candidate->parent;
2181 } else if (target->delegate) {
2182 if (mono_class_is_variant_compatible (target, candidate, TRUE))
2183 return TRUE;
2185 return FALSE;
2188 if (mono_class_is_assignable_from (target, candidate))
2189 return TRUE;
2191 if (!MONO_CLASS_IS_INTERFACE (target) || !mono_class_is_ginst (target) || candidate->rank != 1)
2192 return FALSE;
2194 iface_gtd = mono_class_get_generic_class (target)->container_class;
2195 if (iface_gtd != mono_defaults.generic_ilist_class && iface_gtd != get_icollection_class () && iface_gtd != get_ienumerable_class ())
2196 return FALSE;
2198 target = mono_class_from_mono_type (mono_class_get_generic_class (target)->context.class_inst->type_argv [0]);
2199 candidate = candidate->element_class;
2201 return TRUE;
2204 /*Verify if type 'candidate' can be stored in type 'target'.
2206 * If strict, check for the underlying type and not the verification stack types
2208 static gboolean
2209 verify_type_compatibility_full (VerifyContext *ctx, MonoType *target, MonoType *candidate, gboolean strict)
2211 #define IS_ONE_OF3(T, A, B, C) (T == A || T == B || T == C)
2212 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
2214 MonoType *original_candidate = candidate;
2215 VERIFIER_DEBUG ( printf ("checking type compatibility %s x %s strict %d\n", mono_type_full_name (target), mono_type_full_name (candidate), strict); );
2217 /*only one is byref */
2218 if (candidate->byref ^ target->byref) {
2219 /* converting from native int to byref*/
2220 if (get_stack_type (candidate) == TYPE_NATIVE_INT && target->byref) {
2221 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("using byref native int at 0x%04x", ctx->ip_offset));
2222 return TRUE;
2224 return FALSE;
2226 strict |= target->byref;
2227 /*From now on we don't care about byref anymore, so it's ok to discard it here*/
2228 candidate = mono_type_get_underlying_type_any (candidate);
2230 handle_enum:
2231 switch (target->type) {
2232 case MONO_TYPE_VOID:
2233 return candidate->type == MONO_TYPE_VOID;
2234 case MONO_TYPE_I1:
2235 case MONO_TYPE_U1:
2236 case MONO_TYPE_BOOLEAN:
2237 if (strict)
2238 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I1, MONO_TYPE_U1, MONO_TYPE_BOOLEAN);
2239 case MONO_TYPE_I2:
2240 case MONO_TYPE_U2:
2241 case MONO_TYPE_CHAR:
2242 if (strict)
2243 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I2, MONO_TYPE_U2, MONO_TYPE_CHAR);
2244 case MONO_TYPE_I4:
2245 case MONO_TYPE_U4: {
2246 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2247 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2248 if (strict)
2249 return is_native_int || is_int4;
2250 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2253 case MONO_TYPE_I8:
2254 case MONO_TYPE_U8:
2255 return IS_ONE_OF2 (candidate->type, MONO_TYPE_I8, MONO_TYPE_U8);
2257 case MONO_TYPE_R4:
2258 case MONO_TYPE_R8:
2259 if (strict)
2260 return candidate->type == target->type;
2261 return IS_ONE_OF2 (candidate->type, MONO_TYPE_R4, MONO_TYPE_R8);
2263 case MONO_TYPE_I:
2264 case MONO_TYPE_U: {
2265 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2266 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2267 if (strict)
2268 return is_native_int || is_int4;
2269 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2272 case MONO_TYPE_PTR:
2273 if (candidate->type != MONO_TYPE_PTR)
2274 return FALSE;
2275 /* check the underlying type */
2276 return verify_type_compatibility_full (ctx, target->data.type, candidate->data.type, TRUE);
2278 case MONO_TYPE_FNPTR: {
2279 MonoMethodSignature *left, *right;
2280 if (candidate->type != MONO_TYPE_FNPTR)
2281 return FALSE;
2283 left = mono_type_get_signature (target);
2284 right = mono_type_get_signature (candidate);
2285 return mono_metadata_signature_equal (left, right) && left->call_convention == right->call_convention;
2288 case MONO_TYPE_GENERICINST: {
2289 MonoClass *target_klass;
2290 MonoClass *candidate_klass;
2291 if (mono_type_is_enum_type (target)) {
2292 target = mono_type_get_underlying_type_any (target);
2293 if (!target)
2294 return FALSE;
2295 goto handle_enum;
2298 * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
2299 * to take boxing status into account.
2301 if (mono_type_is_generic_argument (original_candidate))
2302 return FALSE;
2304 target_klass = mono_class_from_mono_type (target);
2305 candidate_klass = mono_class_from_mono_type (candidate);
2306 if (mono_class_is_nullable (target_klass)) {
2307 if (!mono_class_is_nullable (candidate_klass))
2308 return FALSE;
2309 return target_klass == candidate_klass;
2311 return verifier_class_is_assignable_from (target_klass, candidate_klass);
2314 case MONO_TYPE_STRING:
2315 return candidate->type == MONO_TYPE_STRING;
2317 case MONO_TYPE_CLASS:
2319 * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
2320 * to take boxing status into account.
2322 if (mono_type_is_generic_argument (original_candidate))
2323 return FALSE;
2325 if (candidate->type == MONO_TYPE_VALUETYPE)
2326 return FALSE;
2328 /* If candidate is an enum it should return true for System.Enum and supertypes.
2329 * That's why here we use the original type and not the underlying type.
2331 return verifier_class_is_assignable_from (target->data.klass, mono_class_from_mono_type (original_candidate));
2333 case MONO_TYPE_OBJECT:
2334 return MONO_TYPE_IS_REFERENCE (candidate);
2336 case MONO_TYPE_SZARRAY: {
2337 MonoClass *left;
2338 MonoClass *right;
2339 if (candidate->type != MONO_TYPE_SZARRAY)
2340 return FALSE;
2342 left = mono_class_from_mono_type (target);
2343 right = mono_class_from_mono_type (candidate);
2345 return verifier_class_is_assignable_from (left, right);
2348 case MONO_TYPE_ARRAY:
2349 if (candidate->type != MONO_TYPE_ARRAY)
2350 return FALSE;
2351 return is_array_type_compatible (target, candidate);
2353 case MONO_TYPE_TYPEDBYREF:
2354 return candidate->type == MONO_TYPE_TYPEDBYREF;
2356 case MONO_TYPE_VALUETYPE: {
2357 MonoClass *target_klass;
2358 MonoClass *candidate_klass;
2360 if (candidate->type == MONO_TYPE_CLASS)
2361 return FALSE;
2363 target_klass = mono_class_from_mono_type (target);
2364 candidate_klass = mono_class_from_mono_type (candidate);
2365 if (target_klass == candidate_klass)
2366 return TRUE;
2367 if (mono_type_is_enum_type (target)) {
2368 target = mono_type_get_underlying_type_any (target);
2369 if (!target)
2370 return FALSE;
2371 goto handle_enum;
2373 return FALSE;
2376 case MONO_TYPE_VAR:
2377 if (candidate->type != MONO_TYPE_VAR)
2378 return FALSE;
2379 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2381 case MONO_TYPE_MVAR:
2382 if (candidate->type != MONO_TYPE_MVAR)
2383 return FALSE;
2384 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2386 default:
2387 VERIFIER_DEBUG ( printf ("unknown store type %d\n", target->type); );
2388 g_assert_not_reached ();
2389 return FALSE;
2391 return 1;
2392 #undef IS_ONE_OF3
2393 #undef IS_ONE_OF2
2396 static gboolean
2397 verify_type_compatibility (VerifyContext *ctx, MonoType *target, MonoType *candidate)
2399 return verify_type_compatibility_full (ctx, target, candidate, FALSE);
2403 * Returns the generic param bound to the context been verified.
2406 static MonoGenericParam*
2407 get_generic_param (VerifyContext *ctx, MonoType *param)
2409 guint16 param_num = mono_type_get_generic_param_num (param);
2410 if (param->type == MONO_TYPE_VAR) {
2411 if (!ctx->generic_context->class_inst || ctx->generic_context->class_inst->type_argc <= param_num) {
2412 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic type argument %d", param_num));
2413 return NULL;
2415 return ctx->generic_context->class_inst->type_argv [param_num]->data.generic_param;
2418 /*param must be a MVAR */
2419 if (!ctx->generic_context->method_inst || ctx->generic_context->method_inst->type_argc <= param_num) {
2420 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic method argument %d", param_num));
2421 return NULL;
2423 return ctx->generic_context->method_inst->type_argv [param_num]->data.generic_param;
2427 static gboolean
2428 recursive_boxed_constraint_type_check (VerifyContext *ctx, MonoType *type, MonoClass *constraint_class, int recursion_level)
2430 MonoType *constraint_type = &constraint_class->byval_arg;
2431 if (recursion_level <= 0)
2432 return FALSE;
2434 if (verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (constraint_type), FALSE))
2435 return TRUE;
2437 if (mono_type_is_generic_argument (constraint_type)) {
2438 MonoGenericParam *param = get_generic_param (ctx, constraint_type);
2439 MonoClass **klass;
2440 if (!param)
2441 return FALSE;
2442 for (klass = mono_generic_param_info (param)->constraints; klass && *klass; ++klass) {
2443 if (recursive_boxed_constraint_type_check (ctx, type, *klass, recursion_level - 1))
2444 return TRUE;
2447 return FALSE;
2450 /**
2451 * is_compatible_boxed_valuetype:
2453 * Returns: TRUE if @candidate / @stack is a valid boxed valuetype.
2455 * @type The source type. It it tested to be of the proper type.
2456 * @candidate type of the boxed valuetype.
2457 * @stack stack slot of the boxed valuetype, separate from @candidade since one could be changed before calling this function
2458 * @strict if TRUE candidate must be boxed compatible to the target type
2461 static gboolean
2462 is_compatible_boxed_valuetype (VerifyContext *ctx, MonoType *type, MonoType *candidate, ILStackDesc *stack, gboolean strict)
2464 if (!stack_slot_is_boxed_value (stack))
2465 return FALSE;
2466 if (type->byref || candidate->byref)
2467 return FALSE;
2469 if (mono_type_is_generic_argument (candidate)) {
2470 MonoGenericParam *param = get_generic_param (ctx, candidate);
2471 MonoClass **klass;
2472 if (!param)
2473 return FALSE;
2475 for (klass = mono_generic_param_info (param)->constraints; klass && *klass; ++klass) {
2476 /*256 should be enough since there can't be more than 255 generic arguments.*/
2477 if (recursive_boxed_constraint_type_check (ctx, type, *klass, 256))
2478 return TRUE;
2482 if (mono_type_is_generic_argument (type))
2483 return FALSE;
2485 if (!strict)
2486 return TRUE;
2488 return MONO_TYPE_IS_REFERENCE (type) && verifier_class_is_assignable_from (mono_class_from_mono_type (type), mono_class_from_mono_type (candidate));
2491 static int
2492 verify_stack_type_compatibility_full (VerifyContext *ctx, MonoType *type, ILStackDesc *stack, gboolean drop_byref, gboolean valuetype_must_be_boxed)
2494 MonoType *candidate = mono_type_from_stack_slot (stack);
2495 if (MONO_TYPE_IS_REFERENCE (type) && !type->byref && stack_slot_is_null_literal (stack))
2496 return TRUE;
2498 if (is_compatible_boxed_valuetype (ctx, type, candidate, stack, TRUE))
2499 return TRUE;
2501 if (valuetype_must_be_boxed && !stack_slot_is_boxed_value (stack) && !MONO_TYPE_IS_REFERENCE (candidate))
2502 return FALSE;
2504 if (!valuetype_must_be_boxed && stack_slot_is_boxed_value (stack))
2505 return FALSE;
2507 if (drop_byref)
2508 return verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (candidate), FALSE);
2510 /* Handle how Roslyn emit fixed statements by encoding it as byref */
2511 if (type->byref && candidate->byref && (type->type == MONO_TYPE_I) && !mono_type_is_reference (candidate)) {
2512 if (!IS_STRICT_MODE (ctx))
2513 return TRUE;
2516 return verify_type_compatibility_full (ctx, type, candidate, FALSE);
2519 static int
2520 verify_stack_type_compatibility (VerifyContext *ctx, MonoType *type, ILStackDesc *stack)
2522 return verify_stack_type_compatibility_full (ctx, type, stack, FALSE, FALSE);
2525 static gboolean
2526 mono_delegate_type_equal (MonoType *target, MonoType *candidate)
2528 if (candidate->byref ^ target->byref)
2529 return FALSE;
2531 switch (target->type) {
2532 case MONO_TYPE_VOID:
2533 case MONO_TYPE_I1:
2534 case MONO_TYPE_U1:
2535 case MONO_TYPE_BOOLEAN:
2536 case MONO_TYPE_I2:
2537 case MONO_TYPE_U2:
2538 case MONO_TYPE_CHAR:
2539 case MONO_TYPE_I4:
2540 case MONO_TYPE_U4:
2541 case MONO_TYPE_I8:
2542 case MONO_TYPE_U8:
2543 case MONO_TYPE_R4:
2544 case MONO_TYPE_R8:
2545 case MONO_TYPE_I:
2546 case MONO_TYPE_U:
2547 case MONO_TYPE_STRING:
2548 case MONO_TYPE_TYPEDBYREF:
2549 return candidate->type == target->type;
2551 case MONO_TYPE_PTR:
2552 if (candidate->type != MONO_TYPE_PTR)
2553 return FALSE;
2554 return mono_delegate_type_equal (target->data.type, candidate->data.type);
2556 case MONO_TYPE_FNPTR:
2557 if (candidate->type != MONO_TYPE_FNPTR)
2558 return FALSE;
2559 return mono_delegate_signature_equal (mono_type_get_signature (target), mono_type_get_signature (candidate), FALSE);
2561 case MONO_TYPE_GENERICINST: {
2562 MonoClass *target_klass;
2563 MonoClass *candidate_klass;
2564 target_klass = mono_class_from_mono_type (target);
2565 candidate_klass = mono_class_from_mono_type (candidate);
2566 /*FIXME handle nullables and enum*/
2567 return verifier_class_is_assignable_from (target_klass, candidate_klass);
2569 case MONO_TYPE_OBJECT:
2570 return MONO_TYPE_IS_REFERENCE (candidate);
2572 case MONO_TYPE_CLASS:
2573 return verifier_class_is_assignable_from(target->data.klass, mono_class_from_mono_type (candidate));
2575 case MONO_TYPE_SZARRAY:
2576 if (candidate->type != MONO_TYPE_SZARRAY)
2577 return FALSE;
2578 return verifier_class_is_assignable_from (mono_class_from_mono_type (target)->element_class, mono_class_from_mono_type (candidate)->element_class);
2580 case MONO_TYPE_ARRAY:
2581 if (candidate->type != MONO_TYPE_ARRAY)
2582 return FALSE;
2583 return is_array_type_compatible (target, candidate);
2585 case MONO_TYPE_VALUETYPE:
2586 /*FIXME handle nullables and enum*/
2587 return mono_class_from_mono_type (candidate) == mono_class_from_mono_type (target);
2589 case MONO_TYPE_VAR:
2590 return candidate->type == MONO_TYPE_VAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2591 return FALSE;
2593 case MONO_TYPE_MVAR:
2594 return candidate->type == MONO_TYPE_MVAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2595 return FALSE;
2597 default:
2598 VERIFIER_DEBUG ( printf ("Unknown type %d. Implement me!\n", target->type); );
2599 g_assert_not_reached ();
2600 return FALSE;
2604 static gboolean
2605 mono_delegate_param_equal (MonoType *delegate, MonoType *method)
2607 if (mono_metadata_type_equal_full (delegate, method, TRUE))
2608 return TRUE;
2610 return mono_delegate_type_equal (method, delegate);
2613 static gboolean
2614 mono_delegate_ret_equal (MonoType *delegate, MonoType *method)
2616 if (mono_metadata_type_equal_full (delegate, method, TRUE))
2617 return TRUE;
2619 return mono_delegate_type_equal (delegate, method);
2623 * mono_delegate_signature_equal:
2625 * Compare two signatures in the way expected by delegates.
2627 * This function only exists due to the fact that it should ignore the 'has_this' part of the signature.
2629 * FIXME can this function be eliminated and proper metadata functionality be used?
2631 static gboolean
2632 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn)
2634 int i;
2635 int method_offset = is_static_ldftn ? 1 : 0;
2637 if (delegate_sig->param_count + method_offset != method_sig->param_count)
2638 return FALSE;
2640 if (delegate_sig->call_convention != method_sig->call_convention)
2641 return FALSE;
2643 for (i = 0; i < delegate_sig->param_count; i++) {
2644 MonoType *p1 = delegate_sig->params [i];
2645 MonoType *p2 = method_sig->params [i + method_offset];
2647 if (!mono_delegate_param_equal (p1, p2))
2648 return FALSE;
2651 if (!mono_delegate_ret_equal (delegate_sig->ret, method_sig->ret))
2652 return FALSE;
2654 return TRUE;
2657 gboolean
2658 mono_verifier_is_signature_compatible (MonoMethodSignature *target, MonoMethodSignature *candidate)
2660 return mono_delegate_signature_equal (target, candidate, FALSE);
2664 * verify_ldftn_delegate:
2666 * Verify properties of ldftn based delegates.
2668 static void
2669 verify_ldftn_delegate (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2671 MonoMethod *method = funptr->method;
2673 /*ldftn non-final virtuals only allowed if method is not static,
2674 * the object is a this arg (comes from a ldarg.0), and there is no starg.0.
2675 * This rules doesn't apply if the object on stack is a boxed valuetype.
2677 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !mono_class_is_sealed (method->klass) && !stack_slot_is_boxed_value (value)) {
2678 /*A stdarg 0 must not happen, we fail here only in fail fast mode to avoid double error reports*/
2679 if (IS_FAIL_FAST_MODE (ctx) && ctx->has_this_store)
2680 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at 0x%04x", ctx->ip_offset));
2682 /*current method must not be static*/
2683 if (ctx->method->flags & METHOD_ATTRIBUTE_STATIC)
2684 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function at 0x%04x", ctx->ip_offset));
2686 /*value is the this pointer, loaded using ldarg.0 */
2687 if (!stack_slot_is_this_pointer (value))
2688 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));
2690 ctx->code [ctx->ip_offset].flags |= IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL;
2695 * verify_delegate_compatibility:
2697 * Verify delegate creation sequence.
2700 static void
2701 verify_delegate_compatibility (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2703 #define IS_VALID_OPCODE(offset, opcode) (ip [ip_offset - offset] == opcode && (ctx->code [ip_offset - offset].flags & IL_CODE_FLAG_SEEN))
2704 #define IS_LOAD_FUN_PTR(kind) (IS_VALID_OPCODE (6, CEE_PREFIX1) && ip [ip_offset - 5] == kind)
2706 MonoMethod *invoke, *method;
2707 const guint8 *ip = ctx->header->code;
2708 guint32 ip_offset = ctx->ip_offset;
2709 gboolean is_static_ldftn = FALSE, is_first_arg_bound = FALSE;
2711 if (stack_slot_get_type (funptr) != TYPE_PTR || !funptr->method) {
2712 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid function pointer parameter for delegate constructor at 0x%04x", ctx->ip_offset));
2713 return;
2716 invoke = mono_get_delegate_invoke (delegate);
2717 method = funptr->method;
2719 if (!method || !mono_method_signature (method)) {
2720 char *name = mono_type_get_full_name (delegate);
2721 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid method on stack to create delegate %s construction at 0x%04x", name, ctx->ip_offset));
2722 g_free (name);
2723 return;
2726 if (!invoke || !mono_method_signature (invoke)) {
2727 char *name = mono_type_get_full_name (delegate);
2728 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Delegate type %s with bad Invoke method at 0x%04x", name, ctx->ip_offset));
2729 g_free (name);
2730 return;
2733 is_static_ldftn = (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) && method->flags & METHOD_ATTRIBUTE_STATIC;
2735 if (is_static_ldftn)
2736 is_first_arg_bound = mono_method_signature (invoke)->param_count + 1 == mono_method_signature (method)->param_count;
2738 if (!mono_delegate_signature_equal (mono_method_signature (invoke), mono_method_signature (method), is_first_arg_bound)) {
2739 char *fun_sig = mono_signature_get_desc (mono_method_signature (method), FALSE);
2740 char *invoke_sig = mono_signature_get_desc (mono_method_signature (invoke), FALSE);
2741 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));
2742 g_free (fun_sig);
2743 g_free (invoke_sig);
2747 * Delegate code sequences:
2748 * [-6] ldftn token
2749 * newobj ...
2752 * [-7] dup
2753 * [-6] ldvirtftn token
2754 * newobj ...
2756 * ldftn sequence:*/
2757 if (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) {
2758 verify_ldftn_delegate (ctx, delegate, value, funptr);
2759 } else if (ip_offset > 6 && IS_VALID_OPCODE (7, CEE_DUP) && IS_LOAD_FUN_PTR (CEE_LDVIRTFTN)) {
2760 ctx->code [ip_offset - 6].flags |= IL_CODE_DELEGATE_SEQUENCE;
2761 }else {
2762 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid code sequence for delegate creation at 0x%04x", ctx->ip_offset));
2764 ctx->code [ip_offset].flags |= IL_CODE_DELEGATE_SEQUENCE;
2766 //general tests
2767 if (is_first_arg_bound) {
2768 if (mono_method_signature (method)->param_count == 0 || !verify_stack_type_compatibility_full (ctx, mono_method_signature (method)->params [0], value, FALSE, TRUE))
2769 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2770 } else {
2771 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
2772 if (!stack_slot_is_null_literal (value))
2773 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Non-null this args used with static function for delegate creation at 0x%04x", ctx->ip_offset));
2774 } else {
2775 if (!verify_stack_type_compatibility_full (ctx, &method->klass->byval_arg, value, FALSE, TRUE) && !stack_slot_is_null_literal (value))
2776 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2780 if (stack_slot_get_type (value) != TYPE_COMPLEX)
2781 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid first parameter for delegate creation at 0x%04x", ctx->ip_offset));
2783 #undef IS_VALID_OPCODE
2784 #undef IS_LOAD_FUN_PTR
2787 /* implement the opcode checks*/
2788 static void
2789 push_arg (VerifyContext *ctx, unsigned int arg, int take_addr)
2791 ILStackDesc *top;
2793 if (arg >= ctx->max_args) {
2794 if (take_addr)
2795 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2796 else {
2797 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2798 if (check_overflow (ctx)) //FIXME: what sane value could we ever push?
2799 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
2801 } else if (check_overflow (ctx)) {
2802 /*We must let the value be pushed, otherwise we would get an underflow error*/
2803 check_unverifiable_type (ctx, ctx->params [arg]);
2804 if (ctx->params [arg]->byref && take_addr)
2805 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2806 top = stack_push (ctx);
2807 if (!set_stack_value (ctx, top, ctx->params [arg], take_addr))
2808 return;
2810 if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC)) {
2811 if (take_addr)
2812 ctx->has_this_store = TRUE;
2813 else
2814 top->stype |= THIS_POINTER_MASK;
2815 if (mono_method_is_constructor (ctx->method) && !ctx->super_ctor_called && !ctx->method->klass->valuetype)
2816 top->stype |= UNINIT_THIS_MASK;
2821 static void
2822 push_local (VerifyContext *ctx, guint32 arg, int take_addr)
2824 if (arg >= ctx->num_locals) {
2825 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local %d", arg + 1));
2826 } else if (check_overflow (ctx)) {
2827 /*We must let the value be pushed, otherwise we would get an underflow error*/
2828 check_unverifiable_type (ctx, ctx->locals [arg]);
2829 if (ctx->locals [arg]->byref && take_addr)
2830 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2832 set_stack_value (ctx, stack_push (ctx), ctx->locals [arg], take_addr);
2836 static void
2837 store_arg (VerifyContext *ctx, guint32 arg)
2839 ILStackDesc *value;
2841 if (arg >= ctx->max_args) {
2842 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", arg + 1, ctx->ip_offset));
2843 if (check_underflow (ctx, 1))
2844 stack_pop (ctx);
2845 return;
2848 if (check_underflow (ctx, 1)) {
2849 value = stack_pop (ctx);
2850 if (!verify_stack_type_compatibility (ctx, ctx->params [arg], value)) {
2851 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in argument store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
2854 if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC))
2855 ctx->has_this_store = 1;
2858 static void
2859 store_local (VerifyContext *ctx, guint32 arg)
2861 ILStackDesc *value;
2862 if (arg >= ctx->num_locals) {
2863 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", arg + 1, ctx->ip_offset));
2864 return;
2867 /*TODO verify definite assigment */
2868 if (!check_underflow (ctx, 1))
2869 return;
2871 value = stack_pop (ctx);
2872 if (ctx->locals [arg]->byref && stack_slot_is_managed_mutability_pointer (value))
2873 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly managed reference when storing on a local variable at 0x%04x", ctx->ip_offset));
2875 if (!verify_stack_type_compatibility (ctx, ctx->locals [arg], value)) {
2876 char *expected = mono_type_full_name (ctx->locals [arg]);
2877 char *found = stack_slot_full_name (value);
2878 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type '%s' on stack cannot be stored to local %d with type '%s' at 0x%04x",
2879 found,
2880 arg,
2881 expected,
2882 ctx->ip_offset));
2883 g_free (expected);
2884 g_free (found);
2888 /*FIXME add and sub needs special care here*/
2889 static void
2890 do_binop (VerifyContext *ctx, unsigned int opcode, const unsigned char table [TYPE_MAX][TYPE_MAX])
2892 ILStackDesc *a, *b, *top;
2893 int idxa, idxb, complexMerge = 0;
2894 unsigned char res;
2896 if (!check_underflow (ctx, 2))
2897 return;
2898 b = stack_pop (ctx);
2899 a = stack_pop (ctx);
2901 idxa = stack_slot_get_underlying_type (a);
2902 if (stack_slot_is_managed_pointer (a)) {
2903 idxa = TYPE_PTR;
2904 complexMerge = 1;
2907 idxb = stack_slot_get_underlying_type (b);
2908 if (stack_slot_is_managed_pointer (b)) {
2909 idxb = TYPE_PTR;
2910 complexMerge = 2;
2913 --idxa;
2914 --idxb;
2915 res = table [idxa][idxb];
2917 VERIFIER_DEBUG ( printf ("binop res %d\n", res); );
2918 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
2920 top = stack_push (ctx);
2921 if (res == TYPE_INV) {
2922 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)));
2923 copy_stack_value (top, a);
2924 return;
2927 if (res & NON_VERIFIABLE_RESULT) {
2928 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)));
2930 res = res & ~NON_VERIFIABLE_RESULT;
2933 if (complexMerge && res == TYPE_PTR) {
2934 if (complexMerge == 1)
2935 copy_stack_value (top, a);
2936 else if (complexMerge == 2)
2937 copy_stack_value (top, b);
2939 * There is no need to merge the type of two pointers.
2940 * The only valid operation is subtraction, that returns a native
2941 * int as result and can be used with any 2 pointer kinds.
2942 * This is valid acording to Patition III 1.1.4
2944 } else
2945 top->stype = res;
2950 static void
2951 do_boolean_branch_op (VerifyContext *ctx, int delta)
2953 int target = ctx->ip_offset + delta;
2954 ILStackDesc *top;
2956 VERIFIER_DEBUG ( printf ("boolean branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
2958 if (target < 0 || target >= ctx->code_size) {
2959 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Boolean branch target out of code at 0x%04x", ctx->ip_offset));
2960 return;
2963 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
2964 case 1:
2965 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2966 break;
2967 case 2:
2968 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2969 return;
2972 ctx->target = target;
2974 if (!check_underflow (ctx, 1))
2975 return;
2977 top = stack_pop (ctx);
2978 if (!is_valid_bool_arg (top))
2979 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));
2981 check_unmanaged_pointer (ctx, top);
2984 static gboolean
2985 stack_slot_is_complex_type_not_reference_type (ILStackDesc *slot)
2987 return stack_slot_get_type (slot) == TYPE_COMPLEX && !MONO_TYPE_IS_REFERENCE (slot->type) && !stack_slot_is_boxed_value (slot);
2990 static gboolean
2991 stack_slot_is_reference_value (ILStackDesc *slot)
2993 return stack_slot_get_type (slot) == TYPE_COMPLEX && (MONO_TYPE_IS_REFERENCE (slot->type) || stack_slot_is_boxed_value (slot));
2996 static void
2997 do_branch_op (VerifyContext *ctx, signed int delta, const unsigned char table [TYPE_MAX][TYPE_MAX])
2999 ILStackDesc *a, *b;
3000 int idxa, idxb;
3001 unsigned char res;
3002 int target = ctx->ip_offset + delta;
3004 VERIFIER_DEBUG ( printf ("branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
3006 if (target < 0 || target >= ctx->code_size) {
3007 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
3008 return;
3011 switch (is_valid_cmp_branch_instruction (ctx->header, ctx->ip_offset, target)) {
3012 case 1: /*FIXME use constants and not magic numbers.*/
3013 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3014 break;
3015 case 2:
3016 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3017 return;
3020 ctx->target = target;
3022 if (!check_underflow (ctx, 2))
3023 return;
3025 b = stack_pop (ctx);
3026 a = stack_pop (ctx);
3028 idxa = stack_slot_get_underlying_type (a);
3029 if (stack_slot_is_managed_pointer (a))
3030 idxa = TYPE_PTR;
3032 idxb = stack_slot_get_underlying_type (b);
3033 if (stack_slot_is_managed_pointer (b))
3034 idxb = TYPE_PTR;
3036 if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
3037 res = TYPE_INV;
3038 } else {
3039 --idxa;
3040 --idxb;
3041 res = table [idxa][idxb];
3044 VERIFIER_DEBUG ( printf ("branch res %d\n", res); );
3045 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
3047 if (res == TYPE_INV) {
3048 CODE_NOT_VERIFIABLE (ctx,
3049 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));
3050 } else if (res & NON_VERIFIABLE_RESULT) {
3051 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));
3052 res = res & ~NON_VERIFIABLE_RESULT;
3056 static void
3057 do_cmp_op (VerifyContext *ctx, const unsigned char table [TYPE_MAX][TYPE_MAX], guint32 opcode)
3059 ILStackDesc *a, *b;
3060 int idxa, idxb;
3061 unsigned char res;
3063 if (!check_underflow (ctx, 2))
3064 return;
3065 b = stack_pop (ctx);
3066 a = stack_pop (ctx);
3068 if (opcode == CEE_CGT_UN) {
3069 if ((stack_slot_is_reference_value (a) && stack_slot_is_null_literal (b)) ||
3070 (stack_slot_is_reference_value (b) && stack_slot_is_null_literal (a))) {
3071 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3072 return;
3076 idxa = stack_slot_get_underlying_type (a);
3077 if (stack_slot_is_managed_pointer (a))
3078 idxa = TYPE_PTR;
3080 idxb = stack_slot_get_underlying_type (b);
3081 if (stack_slot_is_managed_pointer (b))
3082 idxb = TYPE_PTR;
3084 if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
3085 res = TYPE_INV;
3086 } else {
3087 --idxa;
3088 --idxb;
3089 res = table [idxa][idxb];
3092 if(res == TYPE_INV) {
3093 char *left_type = stack_slot_full_name (a);
3094 char *right_type = stack_slot_full_name (b);
3095 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf("Compare instruction applyed to ill formed stack (%s x %s) at 0x%04x", left_type, right_type, ctx->ip_offset));
3096 g_free (left_type);
3097 g_free (right_type);
3098 } else if (res & NON_VERIFIABLE_RESULT) {
3099 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));
3100 res = res & ~NON_VERIFIABLE_RESULT;
3102 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3105 static void
3106 do_ret (VerifyContext *ctx)
3108 MonoType *ret = ctx->signature->ret;
3109 VERIFIER_DEBUG ( printf ("checking ret\n"); );
3110 if (ret->type != MONO_TYPE_VOID) {
3111 ILStackDesc *top;
3112 if (!check_underflow (ctx, 1))
3113 return;
3115 top = stack_pop(ctx);
3117 if (!verify_stack_type_compatibility (ctx, ctx->signature->ret, top)) {
3118 char *ret_type = mono_type_full_name (ctx->signature->ret);
3119 char *stack_type = stack_slot_full_name (top);
3120 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible return value on stack with method signature, expected '%s' but got '%s' at 0x%04x", ret_type, stack_type, ctx->ip_offset));
3121 g_free (stack_type);
3122 g_free (ret_type);
3123 return;
3126 if (ret->byref || ret->type == MONO_TYPE_TYPEDBYREF || mono_type_is_value_type (ret, "System", "ArgIterator") || mono_type_is_value_type (ret, "System", "RuntimeArgumentHandle"))
3127 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method returns byref, TypedReference, ArgIterator or RuntimeArgumentHandle at 0x%04x", ctx->ip_offset));
3130 if (ctx->eval.size > 0) {
3131 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack not empty (%d) after ret at 0x%04x", ctx->eval.size, ctx->ip_offset));
3133 if (in_any_block (ctx->header, ctx->ip_offset))
3134 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ret cannot escape exception blocks at 0x%04x", ctx->ip_offset));
3138 * 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.
3139 * This is illegal but mono_get_method_full decoded it.
3140 * TODO handle calling .ctor outside one or calling the .ctor for other class but super
3142 static void
3143 do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual_)
3145 MonoError error;
3146 int param_count, i;
3147 MonoMethodSignature *sig;
3148 ILStackDesc *value;
3149 MonoMethod *method;
3150 gboolean virt_check_this = FALSE;
3151 gboolean constrained = ctx->prefix_set & PREFIX_CONSTRAINED;
3153 if (!(method = verifier_load_method (ctx, method_token, virtual_ ? "callvirt" : "call")))
3154 return;
3156 if (virtual_) {
3157 CLEAR_PREFIX (ctx, PREFIX_CONSTRAINED);
3159 if (method->klass->valuetype) // && !constrained ???
3160 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with valuetype method at 0x%04x", ctx->ip_offset));
3162 if ((method->flags & METHOD_ATTRIBUTE_STATIC))
3163 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with static method at 0x%04x", ctx->ip_offset));
3165 } else {
3166 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
3167 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use call with an abstract method at 0x%04x", ctx->ip_offset));
3169 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !mono_class_is_sealed (method->klass)) {
3170 virt_check_this = TRUE;
3171 ctx->code [ctx->ip_offset].flags |= IL_CODE_CALL_NONFINAL_VIRTUAL;
3175 if (!(sig = mono_method_get_signature_checked (method, ctx->image, method_token, ctx->generic_context, &error))) {
3176 mono_error_cleanup (&error);
3177 sig = mono_method_get_signature_checked (method, ctx->image, method_token, NULL, &error);
3180 if (!sig) {
3181 char *name = mono_type_get_full_name (method->klass);
3182 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not resolve signature of %s:%s at 0x%04x due to: %s", name, method->name, ctx->ip_offset, mono_error_get_message (&error)));
3183 mono_error_cleanup (&error);
3184 g_free (name);
3185 return;
3188 param_count = sig->param_count + sig->hasthis;
3189 if (!check_underflow (ctx, param_count))
3190 return;
3192 for (i = sig->param_count - 1; i >= 0; --i) {
3193 VERIFIER_DEBUG ( printf ("verifying argument %d\n", i); );
3194 value = stack_pop (ctx);
3195 if (!verify_stack_type_compatibility (ctx, sig->params[i], value)) {
3196 char *stack_name = stack_slot_full_name (value);
3197 char *sig_name = mono_type_full_name (sig->params [i]);
3198 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));
3199 g_free (stack_name);
3200 g_free (sig_name);
3203 if (stack_slot_is_managed_mutability_pointer (value))
3204 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));
3206 if ((ctx->prefix_set & PREFIX_TAIL) && stack_slot_is_managed_pointer (value)) {
3207 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));
3208 return;
3212 if (sig->hasthis) {
3213 MonoType *type = &method->klass->byval_arg;
3214 ILStackDesc copy;
3216 if (mono_method_is_constructor (method) && !method->klass->valuetype) {
3217 if (IS_STRICT_MODE (ctx) && !mono_method_is_constructor (ctx->method))
3218 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor outside one at 0x%04x", ctx->ip_offset));
3219 if (IS_STRICT_MODE (ctx) && method->klass != ctx->method->klass->parent && method->klass != ctx->method->klass)
3220 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor of a type different from this or super at 0x%04x", ctx->ip_offset));
3222 ctx->super_ctor_called = TRUE;
3223 value = stack_pop_safe (ctx);
3224 if (IS_STRICT_MODE (ctx) && (value->stype & THIS_POINTER_MASK) != THIS_POINTER_MASK)
3225 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid 'this ptr' argument for constructor at 0x%04x", ctx->ip_offset));
3226 } else {
3227 value = stack_pop (ctx);
3230 copy_stack_value (&copy, value);
3231 //TODO we should extract this to a 'drop_byref_argument' and use everywhere
3232 //Other parts of the code suffer from the same issue of
3233 copy.type = mono_type_get_type_byval (copy.type);
3234 copy.stype &= ~POINTER_MASK;
3236 if (virt_check_this && !stack_slot_is_this_pointer (value) && !(method->klass->valuetype || stack_slot_is_boxed_value (value)))
3237 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use the call opcode with a non-final virtual method on an object different than the 'this' pointer at 0x%04x", ctx->ip_offset));
3239 if (constrained && virtual_) {
3240 if (!stack_slot_is_managed_pointer (value))
3241 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object is not a managed pointer for a constrained call at 0x%04x", ctx->ip_offset));
3242 if (!mono_metadata_type_equal_full (mono_type_get_type_byval (value->type), mono_type_get_underlying_type (ctx->constrained_type), TRUE))
3243 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object not compatible with constrained type at 0x%04x", ctx->ip_offset));
3244 copy.stype |= BOXED_MASK;
3245 copy.type = ctx->constrained_type;
3246 } else {
3247 if (stack_slot_is_managed_pointer (value) && !mono_class_from_mono_type (value->type)->valuetype)
3248 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));
3250 if (!virtual_ && mono_class_from_mono_type (value->type)->valuetype && !method->klass->valuetype && !stack_slot_is_boxed_value (value))
3251 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a valuetype baseclass at 0x%04x", ctx->ip_offset));
3253 if (virtual_ && mono_class_from_mono_type (value->type)->valuetype && !stack_slot_is_boxed_value (value))
3254 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a valuetype with callvirt at 0x%04x", ctx->ip_offset));
3256 if (method->klass->valuetype && (stack_slot_is_boxed_value (value) || !stack_slot_is_managed_pointer (value)))
3257 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));
3259 if (!verify_stack_type_compatibility (ctx, type, &copy)) {
3260 char *expected = mono_type_full_name (type);
3261 char *effective = stack_slot_full_name (&copy);
3262 char *method_name = mono_method_full_name (method, TRUE);
3263 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",
3264 expected, effective, method_name, ctx->ip_offset));
3265 g_free (method_name);
3266 g_free (effective);
3267 g_free (expected);
3270 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, mono_class_from_mono_type (value->type))) {
3271 char *name = mono_method_full_name (method, TRUE);
3272 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3273 g_free (name);
3276 } else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
3277 char *name = mono_method_full_name (method, TRUE);
3278 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3279 g_free (name);
3282 if (sig->ret->type != MONO_TYPE_VOID) {
3283 if (!mono_type_is_valid_in_context (ctx, sig->ret))
3284 return;
3286 if (check_overflow (ctx)) {
3287 value = stack_push (ctx);
3288 set_stack_value (ctx, value, sig->ret, FALSE);
3289 if ((ctx->prefix_set & PREFIX_READONLY) && method->klass->rank && !strcmp (method->name, "Address")) {
3290 ctx->prefix_set &= ~PREFIX_READONLY;
3291 value->stype |= CMMP_MASK;
3296 if ((ctx->prefix_set & PREFIX_TAIL)) {
3297 if (!mono_delegate_ret_equal (mono_method_signature (ctx->method)->ret, sig->ret))
3298 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call with incompatible return type at 0x%04x", ctx->ip_offset));
3299 if (ctx->header->code [ctx->ip_offset + 5] != CEE_RET)
3300 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call not followed by ret at 0x%04x", ctx->ip_offset));
3305 static void
3306 do_push_static_field (VerifyContext *ctx, int token, gboolean take_addr)
3308 MonoClassField *field;
3309 MonoClass *klass;
3310 if (!check_overflow (ctx))
3311 return;
3312 if (!take_addr)
3313 CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3315 if (!(field = verifier_load_field (ctx, token, &klass, take_addr ? "ldsflda" : "ldsfld")))
3316 return;
3318 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3319 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load non static field at 0x%04x", ctx->ip_offset));
3320 return;
3322 /*taking the address of initonly field only works from the static constructor */
3323 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3324 !(field->parent == ctx->method->klass && (ctx->method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_STATIC)) && !strcmp (".cctor", ctx->method->name)))
3325 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
3327 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3328 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3330 set_stack_value (ctx, stack_push (ctx), field->type, take_addr);
3333 static void
3334 do_store_static_field (VerifyContext *ctx, int token) {
3335 MonoClassField *field;
3336 MonoClass *klass;
3337 ILStackDesc *value;
3338 CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3340 if (!check_underflow (ctx, 1))
3341 return;
3343 value = stack_pop (ctx);
3345 if (!(field = verifier_load_field (ctx, token, &klass, "stsfld")))
3346 return;
3348 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3349 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store non static field at 0x%04x", ctx->ip_offset));
3350 return;
3353 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3354 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type in store static field at 0x%04x", ctx->ip_offset));
3355 return;
3358 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3359 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3361 if (!verify_stack_type_compatibility (ctx, field->type, value)) {
3362 char *stack_name = stack_slot_full_name (value);
3363 char *field_name = mono_type_full_name (field->type);
3364 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type in static field store expected '%s' but found '%s' at 0x%04x",
3365 field_name, stack_name, ctx->ip_offset));
3366 g_free (field_name);
3367 g_free (stack_name);
3371 static gboolean
3372 check_is_valid_type_for_field_ops (VerifyContext *ctx, int token, ILStackDesc *obj, MonoClassField **ret_field, const char *opcode)
3374 MonoClassField *field;
3375 MonoClass *klass;
3376 gboolean is_pointer;
3378 /*must be a reference type, a managed pointer, an unamanaged pointer, or a valuetype*/
3379 if (!(field = verifier_load_field (ctx, token, &klass, opcode)))
3380 return FALSE;
3382 *ret_field = field;
3383 //the value on stack is going to be used as a pointer
3384 is_pointer = stack_slot_get_type (obj) == TYPE_PTR || (stack_slot_get_type (obj) == TYPE_NATIVE_INT && !get_stack_type (&field->parent->byval_arg));
3386 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3387 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type at 0x%04x", ctx->ip_offset));
3388 return FALSE;
3390 g_assert (obj->type);
3392 /*The value on the stack must be a subclass of the defining type of the field*/
3393 /* we need to check if we can load the field from the stack value*/
3394 if (is_pointer) {
3395 if (stack_slot_get_underlying_type (obj) == TYPE_NATIVE_INT)
3396 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Native int is not a verifiable type to reference a field at 0x%04x", ctx->ip_offset));
3398 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3399 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3400 } else {
3401 if (!field->parent->valuetype && stack_slot_is_managed_pointer (obj))
3402 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));
3404 /*a value type can be loaded from a value or a managed pointer, but not a boxed object*/
3405 if (field->parent->valuetype && stack_slot_is_boxed_value (obj))
3406 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));
3408 if (!stack_slot_is_null_literal (obj) && !verify_stack_type_compatibility_full (ctx, &field->parent->byval_arg, obj, TRUE, FALSE)) {
3409 char *found = stack_slot_full_name (obj);
3410 char *expected = mono_type_full_name (&field->parent->byval_arg);
3411 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));
3412 g_free (found);
3413 g_free (expected);
3416 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, mono_class_from_mono_type (obj->type)))
3417 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3420 check_unmanaged_pointer (ctx, obj);
3421 return TRUE;
3424 static void
3425 do_push_field (VerifyContext *ctx, int token, gboolean take_addr)
3427 ILStackDesc *obj;
3428 MonoClassField *field;
3430 if (!take_addr)
3431 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3433 if (!check_underflow (ctx, 1))
3434 return;
3435 obj = stack_pop_safe (ctx);
3437 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, take_addr ? "ldflda" : "ldfld"))
3438 return;
3440 if (take_addr && field->parent->valuetype && !stack_slot_is_managed_pointer (obj))
3441 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a temporary value-type at 0x%04x", ctx->ip_offset));
3443 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3444 !(field->parent == ctx->method->klass && mono_method_is_constructor (ctx->method)))
3445 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
3447 set_stack_value (ctx, stack_push (ctx), field->type, take_addr);
3450 static void
3451 do_store_field (VerifyContext *ctx, int token)
3453 ILStackDesc *value, *obj;
3454 MonoClassField *field;
3455 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3457 if (!check_underflow (ctx, 2))
3458 return;
3460 value = stack_pop (ctx);
3461 obj = stack_pop_safe (ctx);
3463 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, "stfld"))
3464 return;
3466 if (!verify_stack_type_compatibility (ctx, field->type, value))
3467 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in field store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3470 /*TODO proper handle for Nullable<T>*/
3471 static void
3472 do_box_value (VerifyContext *ctx, int klass_token)
3474 ILStackDesc *value;
3475 MonoType *type = get_boxable_mono_type (ctx, klass_token, "box");
3476 MonoClass *klass;
3478 if (!type)
3479 return;
3481 if (!check_underflow (ctx, 1))
3482 return;
3484 value = stack_pop (ctx);
3485 /*box is a nop for reference types*/
3487 if (stack_slot_get_underlying_type (value) == TYPE_COMPLEX && MONO_TYPE_IS_REFERENCE (value->type) && MONO_TYPE_IS_REFERENCE (type)) {
3488 stack_push_stack_val (ctx, value)->stype |= BOXED_MASK;
3489 return;
3493 if (!verify_stack_type_compatibility (ctx, type, value))
3494 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for boxing operation at 0x%04x", ctx->ip_offset));
3496 klass = mono_class_from_mono_type (type);
3497 if (mono_class_is_nullable (klass))
3498 type = &mono_class_get_nullable_param (klass)->byval_arg;
3499 stack_push_val (ctx, TYPE_COMPLEX | BOXED_MASK, type);
3502 static void
3503 do_unbox_value (VerifyContext *ctx, int klass_token)
3505 ILStackDesc *value;
3506 MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox");
3508 if (!type)
3509 return;
3511 if (!check_underflow (ctx, 1))
3512 return;
3514 if (!mono_class_from_mono_type (type)->valuetype)
3515 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid reference type for unbox at 0x%04x", ctx->ip_offset));
3517 value = stack_pop (ctx);
3519 /*Value should be: a boxed valuetype or a reference type*/
3520 if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3521 (stack_slot_is_boxed_value (value) || !mono_class_from_mono_type (value->type)->valuetype)))
3522 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));
3524 set_stack_value (ctx, value = stack_push (ctx), mono_type_get_type_byref (type), FALSE);
3525 value->stype |= CMMP_MASK;
3528 static void
3529 do_unbox_any (VerifyContext *ctx, int klass_token)
3531 ILStackDesc *value;
3532 MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox.any");
3534 if (!type)
3535 return;
3537 if (!check_underflow (ctx, 1))
3538 return;
3540 value = stack_pop (ctx);
3542 /*Value should be: a boxed valuetype or a reference type*/
3543 if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3544 (stack_slot_is_boxed_value (value) || !mono_class_from_mono_type (value->type)->valuetype)))
3545 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));
3547 set_stack_value (ctx, stack_push (ctx), type, FALSE);
3550 static void
3551 do_unary_math_op (VerifyContext *ctx, int op)
3553 ILStackDesc *value;
3554 if (!check_underflow (ctx, 1))
3555 return;
3556 value = stack_pop (ctx);
3557 switch (stack_slot_get_type (value)) {
3558 case TYPE_I4:
3559 case TYPE_I8:
3560 case TYPE_NATIVE_INT:
3561 break;
3562 case TYPE_R8:
3563 if (op == CEE_NEG)
3564 break;
3565 case TYPE_COMPLEX: /*only enums are ok*/
3566 if (mono_type_is_enum_type (value->type))
3567 break;
3568 default:
3569 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for unary not at 0x%04x", ctx->ip_offset));
3571 stack_push_stack_val (ctx, value);
3574 static void
3575 do_conversion (VerifyContext *ctx, int kind)
3577 ILStackDesc *value;
3578 if (!check_underflow (ctx, 1))
3579 return;
3580 value = stack_pop (ctx);
3582 switch (stack_slot_get_type (value)) {
3583 case TYPE_I4:
3584 case TYPE_I8:
3585 case TYPE_NATIVE_INT:
3586 case TYPE_R8:
3587 break;
3588 default:
3589 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));
3592 switch (kind) {
3593 case TYPE_I4:
3594 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3595 break;
3596 case TYPE_I8:
3597 stack_push_val (ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
3598 break;
3599 case TYPE_R8:
3600 stack_push_val (ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
3601 break;
3602 case TYPE_NATIVE_INT:
3603 stack_push_val (ctx, TYPE_NATIVE_INT, &mono_defaults.int_class->byval_arg);
3604 break;
3605 default:
3606 g_error ("unknown type %02x in conversion", kind);
3611 static void
3612 do_load_token (VerifyContext *ctx, int token)
3614 MonoError error;
3615 gpointer handle;
3616 MonoClass *handle_class;
3617 if (!check_overflow (ctx))
3618 return;
3620 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
3621 handle = mono_method_get_wrapper_data (ctx->method, token);
3622 handle_class = (MonoClass *)mono_method_get_wrapper_data (ctx->method, token + 1);
3623 if (handle_class == mono_defaults.typehandle_class)
3624 handle = &((MonoClass*)handle)->byval_arg;
3625 } else {
3626 switch (token & 0xff000000) {
3627 case MONO_TOKEN_TYPE_DEF:
3628 case MONO_TOKEN_TYPE_REF:
3629 case MONO_TOKEN_TYPE_SPEC:
3630 case MONO_TOKEN_FIELD_DEF:
3631 case MONO_TOKEN_METHOD_DEF:
3632 case MONO_TOKEN_METHOD_SPEC:
3633 case MONO_TOKEN_MEMBER_REF:
3634 if (!token_bounds_check (ctx->image, token)) {
3635 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));
3636 return;
3638 break;
3639 default:
3640 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));
3641 return;
3644 handle = mono_ldtoken_checked (ctx->image, token, &handle_class, ctx->generic_context, &error);
3647 if (!handle) {
3648 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid token 0x%x for ldtoken at 0x%04x due to %s", token, ctx->ip_offset, mono_error_get_message (&error)));
3649 mono_error_cleanup (&error);
3650 return;
3652 if (handle_class == mono_defaults.typehandle_class) {
3653 mono_type_is_valid_in_context (ctx, (MonoType*)handle);
3654 } else if (handle_class == mono_defaults.methodhandle_class) {
3655 mono_method_is_valid_in_context (ctx, (MonoMethod*)handle);
3656 } else if (handle_class == mono_defaults.fieldhandle_class) {
3657 mono_type_is_valid_in_context (ctx, &((MonoClassField*)handle)->parent->byval_arg);
3658 } else {
3659 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid ldtoken type %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
3661 stack_push_val (ctx, TYPE_COMPLEX, mono_class_get_type (handle_class));
3664 static void
3665 do_ldobj_value (VerifyContext *ctx, int token)
3667 ILStackDesc *value;
3668 MonoType *type = get_boxable_mono_type (ctx, token, "ldobj");
3669 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3671 if (!type)
3672 return;
3674 if (!check_underflow (ctx, 1))
3675 return;
3677 value = stack_pop (ctx);
3678 if (!stack_slot_is_managed_pointer (value)
3679 && stack_slot_get_type (value) != TYPE_NATIVE_INT
3680 && !(stack_slot_get_type (value) == TYPE_PTR && value->type->type != MONO_TYPE_FNPTR)) {
3681 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid argument %s to ldobj at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3682 return;
3685 if (stack_slot_get_type (value) == TYPE_NATIVE_INT)
3686 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Using native pointer to ldobj at 0x%04x", ctx->ip_offset));
3688 /*We have a byval on the stack, but the comparison must be strict. */
3689 if (!verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (value->type), TRUE))
3690 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldojb operation at 0x%04x", ctx->ip_offset));
3692 set_stack_value (ctx, stack_push (ctx), type, FALSE);
3695 static void
3696 do_stobj (VerifyContext *ctx, int token)
3698 ILStackDesc *dest, *src;
3699 MonoType *type = get_boxable_mono_type (ctx, token, "stobj");
3700 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3702 if (!type)
3703 return;
3705 if (!check_underflow (ctx, 2))
3706 return;
3708 src = stack_pop (ctx);
3709 dest = stack_pop (ctx);
3711 if (stack_slot_is_managed_mutability_pointer (dest))
3712 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stobj at 0x%04x", ctx->ip_offset));
3714 if (!stack_slot_is_managed_pointer (dest))
3715 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of stobj operation at 0x%04x", ctx->ip_offset));
3717 if (stack_slot_is_boxed_value (src) && !MONO_TYPE_IS_REFERENCE (src->type) && !MONO_TYPE_IS_REFERENCE (type))
3718 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));
3720 if (!verify_stack_type_compatibility (ctx, type, src)) {
3721 char *type_name = mono_type_full_name (type);
3722 char *src_name = stack_slot_full_name (src);
3723 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));
3724 g_free (type_name);
3725 g_free (src_name);
3728 if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3729 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of stobj don't match at 0x%04x", ctx->ip_offset));
3732 static void
3733 do_cpobj (VerifyContext *ctx, int token)
3735 ILStackDesc *dest, *src;
3736 MonoType *type = get_boxable_mono_type (ctx, token, "cpobj");
3737 if (!type)
3738 return;
3740 if (!check_underflow (ctx, 2))
3741 return;
3743 src = stack_pop (ctx);
3744 dest = stack_pop (ctx);
3746 if (!stack_slot_is_managed_pointer (src))
3747 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid source of cpobj operation at 0x%04x", ctx->ip_offset));
3749 if (!stack_slot_is_managed_pointer (dest))
3750 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of cpobj operation at 0x%04x", ctx->ip_offset));
3752 if (stack_slot_is_managed_mutability_pointer (dest))
3753 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with cpobj at 0x%04x", ctx->ip_offset));
3755 if (!verify_type_compatibility (ctx, type, mono_type_get_type_byval (src->type)))
3756 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Token and source types of cpobj don't match at 0x%04x", ctx->ip_offset));
3758 if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3759 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of cpobj don't match at 0x%04x", ctx->ip_offset));
3762 static void
3763 do_initobj (VerifyContext *ctx, int token)
3765 ILStackDesc *obj;
3766 MonoType *stack, *type = get_boxable_mono_type (ctx, token, "initobj");
3767 if (!type)
3768 return;
3770 if (!check_underflow (ctx, 1))
3771 return;
3773 obj = stack_pop (ctx);
3775 if (!stack_slot_is_managed_pointer (obj))
3776 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid object address for initobj at 0x%04x", ctx->ip_offset));
3778 if (stack_slot_is_managed_mutability_pointer (obj))
3779 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with initobj at 0x%04x", ctx->ip_offset));
3781 stack = mono_type_get_type_byval (obj->type);
3782 if (MONO_TYPE_IS_REFERENCE (stack)) {
3783 if (!verify_type_compatibility (ctx, stack, type))
3784 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3785 else if (IS_STRICT_MODE (ctx) && !mono_metadata_type_equal (type, stack))
3786 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3787 } else if (!verify_type_compatibility (ctx, stack, type)) {
3788 char *expected_name = mono_type_full_name (type);
3789 char *stack_name = mono_type_full_name (stack);
3791 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));
3792 g_free (expected_name);
3793 g_free (stack_name);
3797 static void
3798 do_newobj (VerifyContext *ctx, int token)
3800 ILStackDesc *value;
3801 int i;
3802 MonoMethodSignature *sig;
3803 MonoMethod *method;
3804 gboolean is_delegate = FALSE;
3806 if (!(method = verifier_load_method (ctx, token, "newobj")))
3807 return;
3809 if (!mono_method_is_constructor (method)) {
3810 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method from token 0x%08x not a constructor at 0x%04x", token, ctx->ip_offset));
3811 return;
3814 if (mono_class_get_flags (method->klass) & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE))
3815 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Trying to instantiate an abstract or interface type at 0x%04x", ctx->ip_offset));
3817 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
3818 char *from = mono_method_full_name (ctx->method, TRUE);
3819 char *to = mono_method_full_name (method, TRUE);
3820 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);
3821 g_free (from);
3822 g_free (to);
3825 //FIXME use mono_method_get_signature_full
3826 sig = mono_method_signature (method);
3827 if (!sig) {
3828 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid constructor signature to newobj at 0x%04x", ctx->ip_offset));
3829 return;
3832 if (!sig->hasthis) {
3833 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid constructor signature missing hasthis at 0x%04x", ctx->ip_offset));
3834 return;
3837 if (!check_underflow (ctx, sig->param_count))
3838 return;
3840 is_delegate = method->klass->parent == mono_defaults.multicastdelegate_class;
3842 if (is_delegate) {
3843 ILStackDesc *funptr;
3844 //first arg is object, second arg is fun ptr
3845 if (sig->param_count != 2) {
3846 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid delegate constructor at 0x%04x", ctx->ip_offset));
3847 return;
3849 funptr = stack_pop (ctx);
3850 value = stack_pop (ctx);
3851 verify_delegate_compatibility (ctx, method->klass, value, funptr);
3852 } else {
3853 for (i = sig->param_count - 1; i >= 0; --i) {
3854 VERIFIER_DEBUG ( printf ("verifying constructor argument %d\n", i); );
3855 value = stack_pop (ctx);
3856 if (!verify_stack_type_compatibility (ctx, sig->params [i], value)) {
3857 char *stack_name = stack_slot_full_name (value);
3858 char *sig_name = mono_type_full_name (sig->params [i]);
3859 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));
3860 g_free (stack_name);
3861 g_free (sig_name);
3864 if (stack_slot_is_managed_mutability_pointer (value))
3865 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer as argument of newobj at 0x%04x", ctx->ip_offset));
3869 if (check_overflow (ctx))
3870 set_stack_value (ctx, stack_push (ctx), &method->klass->byval_arg, FALSE);
3873 static void
3874 do_cast (VerifyContext *ctx, int token, const char *opcode) {
3875 ILStackDesc *value;
3876 MonoType *type;
3877 gboolean is_boxed;
3878 gboolean do_box;
3880 if (!check_underflow (ctx, 1))
3881 return;
3883 if (!(type = get_boxable_mono_type (ctx, token, opcode)))
3884 return;
3886 if (type->byref) {
3887 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid %s type at 0x%04x", opcode, ctx->ip_offset));
3888 return;
3891 value = stack_pop (ctx);
3892 is_boxed = stack_slot_is_boxed_value (value);
3894 if (stack_slot_is_managed_pointer (value))
3895 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
3896 else if (!MONO_TYPE_IS_REFERENCE (value->type) && !is_boxed) {
3897 char *name = stack_slot_full_name (value);
3898 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));
3899 g_free (name);
3902 switch (value->type->type) {
3903 case MONO_TYPE_FNPTR:
3904 case MONO_TYPE_PTR:
3905 case MONO_TYPE_TYPEDBYREF:
3906 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
3907 default:
3908 break;
3911 do_box = is_boxed || mono_type_is_generic_argument(type) || mono_class_from_mono_type (type)->valuetype;
3912 stack_push_val (ctx, TYPE_COMPLEX | (do_box ? BOXED_MASK : 0), type);
3915 static MonoType *
3916 mono_type_from_opcode (int opcode) {
3917 switch (opcode) {
3918 case CEE_LDIND_I1:
3919 case CEE_LDIND_U1:
3920 case CEE_STIND_I1:
3921 case CEE_LDELEM_I1:
3922 case CEE_LDELEM_U1:
3923 case CEE_STELEM_I1:
3924 return &mono_defaults.sbyte_class->byval_arg;
3926 case CEE_LDIND_I2:
3927 case CEE_LDIND_U2:
3928 case CEE_STIND_I2:
3929 case CEE_LDELEM_I2:
3930 case CEE_LDELEM_U2:
3931 case CEE_STELEM_I2:
3932 return &mono_defaults.int16_class->byval_arg;
3934 case CEE_LDIND_I4:
3935 case CEE_LDIND_U4:
3936 case CEE_STIND_I4:
3937 case CEE_LDELEM_I4:
3938 case CEE_LDELEM_U4:
3939 case CEE_STELEM_I4:
3940 return &mono_defaults.int32_class->byval_arg;
3942 case CEE_LDIND_I8:
3943 case CEE_STIND_I8:
3944 case CEE_LDELEM_I8:
3945 case CEE_STELEM_I8:
3946 return &mono_defaults.int64_class->byval_arg;
3948 case CEE_LDIND_R4:
3949 case CEE_STIND_R4:
3950 case CEE_LDELEM_R4:
3951 case CEE_STELEM_R4:
3952 return &mono_defaults.single_class->byval_arg;
3954 case CEE_LDIND_R8:
3955 case CEE_STIND_R8:
3956 case CEE_LDELEM_R8:
3957 case CEE_STELEM_R8:
3958 return &mono_defaults.double_class->byval_arg;
3960 case CEE_LDIND_I:
3961 case CEE_STIND_I:
3962 case CEE_LDELEM_I:
3963 case CEE_STELEM_I:
3964 return &mono_defaults.int_class->byval_arg;
3966 case CEE_LDIND_REF:
3967 case CEE_STIND_REF:
3968 case CEE_LDELEM_REF:
3969 case CEE_STELEM_REF:
3970 return &mono_defaults.object_class->byval_arg;
3972 default:
3973 g_error ("unknown opcode %02x in mono_type_from_opcode ", opcode);
3974 return NULL;
3978 static void
3979 do_load_indirect (VerifyContext *ctx, int opcode)
3981 ILStackDesc *value;
3982 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3984 if (!check_underflow (ctx, 1))
3985 return;
3987 value = stack_pop (ctx);
3988 if (!stack_slot_is_managed_pointer (value)) {
3989 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Load indirect not using a manager pointer at 0x%04x", ctx->ip_offset));
3990 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
3991 return;
3994 if (opcode == CEE_LDIND_REF) {
3995 if (stack_slot_get_underlying_type (value) != TYPE_COMPLEX || mono_class_from_mono_type (value->type)->valuetype)
3996 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind_ref expected object byref operation at 0x%04x", ctx->ip_offset));
3997 set_stack_value (ctx, stack_push (ctx), mono_type_get_type_byval (value->type), FALSE);
3998 } else {
3999 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (value->type), TRUE))
4000 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4001 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
4005 static void
4006 do_store_indirect (VerifyContext *ctx, int opcode)
4008 ILStackDesc *addr, *val;
4009 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
4011 if (!check_underflow (ctx, 2))
4012 return;
4014 val = stack_pop (ctx);
4015 addr = stack_pop (ctx);
4017 check_unmanaged_pointer (ctx, addr);
4019 if (!stack_slot_is_managed_pointer (addr) && stack_slot_get_type (addr) != TYPE_PTR) {
4020 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid non-pointer argument to stind at 0x%04x", ctx->ip_offset));
4021 return;
4024 if (stack_slot_is_managed_mutability_pointer (addr)) {
4025 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stind at 0x%04x", ctx->ip_offset));
4026 return;
4029 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (addr->type), TRUE))
4030 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid addr type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4032 if (!verify_stack_type_compatibility (ctx, mono_type_from_opcode (opcode), val))
4033 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4036 static void
4037 do_newarr (VerifyContext *ctx, int token)
4039 ILStackDesc *value;
4040 MonoType *type = get_boxable_mono_type (ctx, token, "newarr");
4042 if (!type)
4043 return;
4045 if (!check_underflow (ctx, 1))
4046 return;
4048 value = stack_pop (ctx);
4049 if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
4050 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));
4052 set_stack_value (ctx, stack_push (ctx), mono_class_get_type (mono_array_class_get (mono_class_from_mono_type (type), 1)), FALSE);
4055 /*FIXME handle arrays that are not 0-indexed*/
4056 static void
4057 do_ldlen (VerifyContext *ctx)
4059 ILStackDesc *value;
4061 if (!check_underflow (ctx, 1))
4062 return;
4064 value = stack_pop (ctx);
4066 if (stack_slot_get_type (value) != TYPE_COMPLEX || value->type->type != MONO_TYPE_SZARRAY)
4067 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type for ldlen at 0x%04x", ctx->ip_offset));
4069 stack_push_val (ctx, TYPE_NATIVE_INT, &mono_defaults.int_class->byval_arg);
4072 /*FIXME handle arrays that are not 0-indexed*/
4073 /*FIXME handle readonly prefix and CMMP*/
4074 static void
4075 do_ldelema (VerifyContext *ctx, int klass_token)
4077 ILStackDesc *index, *array, *res;
4078 MonoType *type = get_boxable_mono_type (ctx, klass_token, "ldelema");
4079 gboolean valid;
4081 if (!type)
4082 return;
4084 if (!check_underflow (ctx, 2))
4085 return;
4087 index = stack_pop (ctx);
4088 array = stack_pop (ctx);
4090 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4091 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));
4093 if (!stack_slot_is_null_literal (array)) {
4094 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
4095 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type(%s) for ldelema at 0x%04x", stack_slot_get_name (array), ctx->ip_offset));
4096 else {
4097 if (get_stack_type (type) == TYPE_I4 || get_stack_type (type) == TYPE_NATIVE_INT) {
4098 valid = verify_type_compatibility_full (ctx, type, &array->type->data.klass->byval_arg, TRUE);
4099 } else {
4100 valid = mono_metadata_type_equal (type, &array->type->data.klass->byval_arg);
4102 if (!valid)
4103 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelema at 0x%04x", ctx->ip_offset));
4107 res = stack_push (ctx);
4108 set_stack_value (ctx, res, type, TRUE);
4109 if (ctx->prefix_set & PREFIX_READONLY) {
4110 ctx->prefix_set &= ~PREFIX_READONLY;
4111 res->stype |= CMMP_MASK;
4116 * FIXME handle arrays that are not 0-indexed
4117 * FIXME handle readonly prefix and CMMP
4119 static void
4120 do_ldelem (VerifyContext *ctx, int opcode, int token)
4122 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
4123 ILStackDesc *index, *array;
4124 MonoType *type;
4125 if (!check_underflow (ctx, 2))
4126 return;
4128 if (opcode == CEE_LDELEM) {
4129 if (!(type = verifier_load_type (ctx, token, "ldelem.any"))) {
4130 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
4131 return;
4133 } else {
4134 type = mono_type_from_opcode (opcode);
4137 index = stack_pop (ctx);
4138 array = stack_pop (ctx);
4140 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4141 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));
4143 if (!stack_slot_is_null_literal (array)) {
4144 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
4145 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));
4146 else {
4147 if (opcode == CEE_LDELEM_REF) {
4148 if (array->type->data.klass->valuetype)
4149 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for ldelem.ref 0x%04x", ctx->ip_offset));
4150 type = &array->type->data.klass->byval_arg;
4151 } else {
4152 MonoType *candidate = &array->type->data.klass->byval_arg;
4153 if (IS_STRICT_MODE (ctx)) {
4154 MonoType *underlying_type = mono_type_get_underlying_type_any (type);
4155 MonoType *underlying_candidate = mono_type_get_underlying_type_any (candidate);
4156 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)) ||
4157 (IS_ONE_OF2 (underlying_candidate->type, MONO_TYPE_I4, MONO_TYPE_U4) && IS_ONE_OF2 (underlying_type->type, MONO_TYPE_I, MONO_TYPE_U)))
4158 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
4160 if (!verify_type_compatibility_full (ctx, type, candidate, TRUE))
4161 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
4166 set_stack_value (ctx, stack_push (ctx), type, FALSE);
4167 #undef IS_ONE_OF2
4171 * FIXME handle arrays that are not 0-indexed
4173 static void
4174 do_stelem (VerifyContext *ctx, int opcode, int token)
4176 ILStackDesc *index, *array, *value;
4177 MonoType *type;
4178 if (!check_underflow (ctx, 3))
4179 return;
4181 if (opcode == CEE_STELEM) {
4182 if (!(type = verifier_load_type (ctx, token, "stelem.any"))) {
4183 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
4184 return;
4186 } else {
4187 type = mono_type_from_opcode (opcode);
4190 value = stack_pop (ctx);
4191 index = stack_pop (ctx);
4192 array = stack_pop (ctx);
4194 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4195 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));
4197 if (!stack_slot_is_null_literal (array)) {
4198 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY) {
4199 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));
4200 } else {
4201 if (opcode == CEE_STELEM_REF) {
4202 if (array->type->data.klass->valuetype)
4203 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4204 } else if (!verify_type_compatibility_full (ctx, &array->type->data.klass->byval_arg, type, TRUE)) {
4205 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4209 if (opcode == CEE_STELEM_REF) {
4210 if (!stack_slot_is_boxed_value (value) && mono_class_from_mono_type (value->type)->valuetype)
4211 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4212 } else if (opcode != CEE_STELEM_REF) {
4213 if (!verify_stack_type_compatibility (ctx, type, value))
4214 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4216 if (stack_slot_is_boxed_value (value) && !MONO_TYPE_IS_REFERENCE (value->type) && !MONO_TYPE_IS_REFERENCE (type))
4217 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));
4222 static void
4223 do_throw (VerifyContext *ctx)
4225 ILStackDesc *exception;
4226 if (!check_underflow (ctx, 1))
4227 return;
4228 exception = stack_pop (ctx);
4230 if (!stack_slot_is_null_literal (exception) && !(stack_slot_get_type (exception) == TYPE_COMPLEX && !mono_class_from_mono_type (exception->type)->valuetype))
4231 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type on stack for throw, expected reference type at 0x%04x", ctx->ip_offset));
4233 if (mono_type_is_generic_argument (exception->type) && !stack_slot_is_boxed_value (exception)) {
4234 char *name = mono_type_full_name (exception->type);
4235 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));
4236 g_free (name);
4238 /*The stack is left empty after a throw*/
4239 ctx->eval.size = 0;
4243 static void
4244 do_endfilter (VerifyContext *ctx)
4246 MonoExceptionClause *clause;
4248 if (IS_STRICT_MODE (ctx)) {
4249 if (ctx->eval.size != 1)
4250 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack size must have one item for endfilter at 0x%04x", ctx->ip_offset));
4252 if (ctx->eval.size >= 1 && stack_slot_get_type (stack_pop (ctx)) != TYPE_I4)
4253 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack item type is not an int32 for endfilter at 0x%04x", ctx->ip_offset));
4256 if ((clause = is_correct_endfilter (ctx, ctx->ip_offset))) {
4257 if (IS_STRICT_MODE (ctx)) {
4258 if (ctx->ip_offset != clause->handler_offset - 2)
4259 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
4260 } else {
4261 if ((ctx->ip_offset != clause->handler_offset - 2) && !MONO_OFFSET_IN_HANDLER (clause, ctx->ip_offset))
4262 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
4264 } else {
4265 if (IS_STRICT_MODE (ctx) && !is_unverifiable_endfilter (ctx, ctx->ip_offset))
4266 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4267 else
4268 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4271 ctx->eval.size = 0;
4274 static void
4275 do_leave (VerifyContext *ctx, int delta)
4277 int target = ((gint32)ctx->ip_offset) + delta;
4278 if (target >= ctx->code_size || target < 0)
4279 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
4281 if (!is_correct_leave (ctx->header, ctx->ip_offset, target))
4282 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ctx->ip_offset));
4283 ctx->eval.size = 0;
4284 ctx->target = target;
4288 * do_static_branch:
4290 * Verify br and br.s opcodes.
4292 static void
4293 do_static_branch (VerifyContext *ctx, int delta)
4295 int target = ctx->ip_offset + delta;
4296 if (target < 0 || target >= ctx->code_size) {
4297 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("branch target out of code at 0x%04x", ctx->ip_offset));
4298 return;
4301 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4302 case 1:
4303 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4304 break;
4305 case 2:
4306 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4307 break;
4310 ctx->target = target;
4313 static void
4314 do_switch (VerifyContext *ctx, int count, const unsigned char *data)
4316 int i, base = ctx->ip_offset + 5 + count * 4;
4317 ILStackDesc *value;
4319 if (!check_underflow (ctx, 1))
4320 return;
4322 value = stack_pop (ctx);
4324 if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
4325 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to switch at 0x%04x", ctx->ip_offset));
4327 for (i = 0; i < count; ++i) {
4328 int target = base + read32 (data + i * 4);
4330 if (target < 0 || target >= ctx->code_size) {
4331 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x out of code at 0x%04x", i, ctx->ip_offset));
4332 return;
4335 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4336 case 1:
4337 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4338 break;
4339 case 2:
4340 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4341 return;
4343 merge_stacks (ctx, &ctx->eval, &ctx->code [target], FALSE, TRUE);
4347 static void
4348 do_load_function_ptr (VerifyContext *ctx, guint32 token, gboolean virtual_)
4350 ILStackDesc *top;
4351 MonoMethod *method;
4353 if (virtual_ && !check_underflow (ctx, 1))
4354 return;
4356 if (!virtual_ && !check_overflow (ctx))
4357 return;
4359 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
4360 method = (MonoMethod *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
4361 if (!method) {
4362 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4363 return;
4365 } else {
4366 if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
4367 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4368 return;
4371 if (!(method = verifier_load_method (ctx, token, virtual_ ? "ldvirtfrn" : "ldftn")))
4372 return;
4375 if (mono_method_is_constructor (method))
4376 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldftn with a constructor at 0x%04x", ctx->ip_offset));
4378 if (virtual_) {
4379 ILStackDesc *top = stack_pop (ctx);
4381 if (stack_slot_get_type (top) != TYPE_COMPLEX || top->type->type == MONO_TYPE_VALUETYPE)
4382 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to ldvirtftn at 0x%04x", ctx->ip_offset));
4384 if (method->flags & METHOD_ATTRIBUTE_STATIC)
4385 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldvirtftn with a constructor at 0x%04x", ctx->ip_offset));
4387 if (!verify_stack_type_compatibility (ctx, &method->klass->byval_arg, top))
4388 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unexpected object for ldvirtftn at 0x%04x", ctx->ip_offset));
4391 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL))
4392 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);
4394 top = stack_push_val(ctx, TYPE_PTR, mono_type_create_fnptr_from_mono_method (ctx, method));
4395 top->method = method;
4398 static void
4399 do_sizeof (VerifyContext *ctx, int token)
4401 MonoType *type;
4403 if (!(type = verifier_load_type (ctx, token, "sizeof")))
4404 return;
4406 if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
4407 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type at 0x%04x", ctx->ip_offset));
4408 return;
4411 if (type->type == MONO_TYPE_VOID) {
4412 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type at 0x%04x", ctx->ip_offset));
4413 return;
4416 if (check_overflow (ctx))
4417 set_stack_value (ctx, stack_push (ctx), &mono_defaults.uint32_class->byval_arg, FALSE);
4420 /* Stack top can be of any type, the runtime doesn't care and treat everything as an int. */
4421 static void
4422 do_localloc (VerifyContext *ctx)
4424 if (ctx->eval.size != 1) {
4425 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4426 return;
4429 if (in_any_exception_block (ctx->header, ctx->ip_offset)) {
4430 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4431 return;
4434 /*TODO verify top type*/
4435 /* top = */ stack_pop (ctx);
4437 set_stack_value (ctx, stack_push (ctx), &mono_defaults.int_class->byval_arg, FALSE);
4438 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Instruction localloc in never verifiable at 0x%04x", ctx->ip_offset));
4441 static void
4442 do_ldstr (VerifyContext *ctx, guint32 token)
4444 GSList *error = NULL;
4445 if (ctx->method->wrapper_type == MONO_WRAPPER_NONE && !image_is_dynamic (ctx->image)) {
4446 if (mono_metadata_token_code (token) != MONO_TOKEN_STRING) {
4447 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string token %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4448 return;
4451 if (!mono_verifier_verify_string_signature (ctx->image, mono_metadata_token_index (token), &error)) {
4452 if (error)
4453 ctx->list = g_slist_concat (ctx->list, error);
4454 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string index %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4455 return;
4459 if (check_overflow (ctx))
4460 stack_push_val (ctx, TYPE_COMPLEX, &mono_defaults.string_class->byval_arg);
4463 static void
4464 do_refanyval (VerifyContext *ctx, int token)
4466 ILStackDesc *top;
4467 MonoType *type;
4468 if (!check_underflow (ctx, 1))
4469 return;
4471 if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4472 return;
4474 top = stack_pop (ctx);
4476 if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4477 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));
4479 set_stack_value (ctx, stack_push (ctx), type, TRUE);
4482 static void
4483 do_refanytype (VerifyContext *ctx)
4485 ILStackDesc *top;
4487 if (!check_underflow (ctx, 1))
4488 return;
4490 top = stack_pop (ctx);
4492 if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4493 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));
4495 set_stack_value (ctx, stack_push (ctx), &mono_defaults.typehandle_class->byval_arg, FALSE);
4499 static void
4500 do_mkrefany (VerifyContext *ctx, int token)
4502 ILStackDesc *top;
4503 MonoType *type;
4504 if (!check_underflow (ctx, 1))
4505 return;
4507 if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4508 return;
4510 top = stack_pop (ctx);
4512 if (stack_slot_is_managed_mutability_pointer (top))
4513 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with mkrefany at 0x%04x", ctx->ip_offset));
4515 if (!stack_slot_is_managed_pointer (top)) {
4516 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));
4517 }else {
4518 MonoType *stack_type = mono_type_get_type_byval (top->type);
4519 if (MONO_TYPE_IS_REFERENCE (type) && !mono_metadata_type_equal (type, stack_type))
4520 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4522 if (!MONO_TYPE_IS_REFERENCE (type) && !verify_type_compatibility_full (ctx, type, stack_type, TRUE))
4523 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4526 set_stack_value (ctx, stack_push (ctx), &mono_defaults.typed_reference_class->byval_arg, FALSE);
4529 static void
4530 do_ckfinite (VerifyContext *ctx)
4532 ILStackDesc *top;
4533 if (!check_underflow (ctx, 1))
4534 return;
4536 top = stack_pop (ctx);
4538 if (stack_slot_get_underlying_type (top) != TYPE_R8)
4539 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));
4540 stack_push_stack_val (ctx, top);
4543 * merge_stacks:
4544 * Merge the stacks and perform compat checks. The merge check if types of @from are mergeable with type of @to
4546 * @from holds new values for a given control path
4547 * @to holds the current values of a given control path
4549 * TODO we can eliminate the from argument as all callers pass &ctx->eval
4551 static void
4552 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external)
4554 MonoError error;
4555 int i, j;
4556 stack_init (ctx, to);
4558 if (start) {
4559 if (to->flags == IL_CODE_FLAG_NOT_PROCESSED)
4560 from->size = 0;
4561 else
4562 stack_copy (&ctx->eval, to);
4563 goto end_verify;
4564 } else if (!(to->flags & IL_CODE_STACK_MERGED)) {
4565 stack_copy (to, &ctx->eval);
4566 goto end_verify;
4568 VERIFIER_DEBUG ( printf ("performing stack merge %d x %d\n", from->size, to->size); );
4570 if (from->size != to->size) {
4571 VERIFIER_DEBUG ( printf ("different stack sizes %d x %d at 0x%04x\n", from->size, to->size, ctx->ip_offset); );
4572 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));
4573 goto end_verify;
4576 //FIXME we need to preserve CMMP attributes
4577 //FIXME we must take null literals into consideration.
4578 for (i = 0; i < from->size; ++i) {
4579 ILStackDesc *new_slot = from->stack + i;
4580 ILStackDesc *old_slot = to->stack + i;
4581 MonoType *new_type = mono_type_from_stack_slot (new_slot);
4582 MonoType *old_type = mono_type_from_stack_slot (old_slot);
4583 MonoClass *old_class = mono_class_from_mono_type (old_type);
4584 MonoClass *new_class = mono_class_from_mono_type (new_type);
4585 MonoClass *match_class = NULL;
4587 // S := T then U = S (new value is compatible with current value, keep current)
4588 if (verify_stack_type_compatibility (ctx, old_type, new_slot)) {
4589 copy_stack_value (new_slot, old_slot);
4590 continue;
4593 // T := S then U = T (old value is compatible with current value, use new)
4594 if (verify_stack_type_compatibility (ctx, new_type, old_slot)) {
4595 copy_stack_value (old_slot, new_slot);
4596 continue;
4599 /*Both slots are the same boxed valuetype. Simply copy it.*/
4600 if (stack_slot_is_boxed_value (old_slot) &&
4601 stack_slot_is_boxed_value (new_slot) &&
4602 mono_metadata_type_equal (old_type, new_type)) {
4603 copy_stack_value (new_slot, old_slot);
4604 continue;
4607 if (mono_type_is_generic_argument (old_type) || mono_type_is_generic_argument (new_type)) {
4608 char *old_name = stack_slot_full_name (old_slot);
4609 char *new_name = stack_slot_full_name (new_slot);
4610 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));
4611 g_free (old_name);
4612 g_free (new_name);
4613 goto end_verify;
4616 //both are reference types, use closest common super type
4617 if (!mono_class_from_mono_type (old_type)->valuetype
4618 && !mono_class_from_mono_type (new_type)->valuetype
4619 && !stack_slot_is_managed_pointer (old_slot)
4620 && !stack_slot_is_managed_pointer (new_slot)) {
4622 mono_class_setup_supertypes (old_class);
4623 mono_class_setup_supertypes (new_class);
4625 for (j = MIN (old_class->idepth, new_class->idepth) - 1; j > 0; --j) {
4626 if (mono_metadata_type_equal (&old_class->supertypes [j]->byval_arg, &new_class->supertypes [j]->byval_arg)) {
4627 match_class = old_class->supertypes [j];
4628 goto match_found;
4632 mono_class_setup_interfaces (old_class, &error);
4633 if (!mono_error_ok (&error)) {
4634 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));
4635 mono_error_cleanup (&error);
4636 goto end_verify;
4638 mono_class_setup_interfaces (new_class, &error);
4639 if (!mono_error_ok (&error)) {
4640 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));
4641 mono_error_cleanup (&error);
4642 goto end_verify;
4645 /* if old class is an interface that new class implements */
4646 if (mono_class_is_interface (old_class)) {
4647 if (verifier_class_is_assignable_from (old_class, new_class)) {
4648 match_class = old_class;
4649 goto match_found;
4651 for (j = 0; j < old_class->interface_count; ++j) {
4652 if (verifier_class_is_assignable_from (old_class->interfaces [j], new_class)) {
4653 match_class = old_class->interfaces [j];
4654 goto match_found;
4659 if (mono_class_is_interface (new_class)) {
4660 if (verifier_class_is_assignable_from (new_class, old_class)) {
4661 match_class = new_class;
4662 goto match_found;
4664 for (j = 0; j < new_class->interface_count; ++j) {
4665 if (verifier_class_is_assignable_from (new_class->interfaces [j], old_class)) {
4666 match_class = new_class->interfaces [j];
4667 goto match_found;
4672 //No decent super type found, use object
4673 match_class = mono_defaults.object_class;
4674 goto match_found;
4675 } 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)) {
4676 match_class = mono_defaults.object_class;
4677 goto match_found;
4681 char *old_name = stack_slot_full_name (old_slot);
4682 char *new_name = stack_slot_full_name (new_slot);
4683 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));
4684 g_free (old_name);
4685 g_free (new_name);
4687 set_stack_value (ctx, old_slot, &new_class->byval_arg, stack_slot_is_managed_pointer (old_slot));
4688 goto end_verify;
4690 match_found:
4691 g_assert (match_class);
4692 set_stack_value (ctx, old_slot, &match_class->byval_arg, stack_slot_is_managed_pointer (old_slot));
4693 set_stack_value (ctx, new_slot, &match_class->byval_arg, stack_slot_is_managed_pointer (old_slot));
4694 continue;
4697 end_verify:
4698 if (external)
4699 to->flags |= IL_CODE_FLAG_WAS_TARGET;
4700 to->flags |= IL_CODE_STACK_MERGED;
4703 #define HANDLER_START(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER ? (clause)->data.filter_offset : clause->handler_offset)
4704 #define IS_CATCH_OR_FILTER(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER || (clause)->flags == MONO_EXCEPTION_CLAUSE_NONE)
4707 * is_clause_in_range :
4709 * Returns TRUE if either the protected block or the handler of @clause is in the @start - @end range.
4711 static gboolean
4712 is_clause_in_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4714 if (clause->try_offset >= start && clause->try_offset < end)
4715 return TRUE;
4716 if (HANDLER_START (clause) >= start && HANDLER_START (clause) < end)
4717 return TRUE;
4718 return FALSE;
4722 * is_clause_inside_range :
4724 * Returns TRUE if @clause lies completely inside the @start - @end range.
4726 static gboolean
4727 is_clause_inside_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4729 if (clause->try_offset < start || (clause->try_offset + clause->try_len) > end)
4730 return FALSE;
4731 if (HANDLER_START (clause) < start || (clause->handler_offset + clause->handler_len) > end)
4732 return FALSE;
4733 return TRUE;
4737 * is_clause_nested :
4739 * Returns TRUE if @nested is nested in @clause.
4741 static gboolean
4742 is_clause_nested (MonoExceptionClause *clause, MonoExceptionClause *nested)
4744 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (nested, clause->data.filter_offset, clause->handler_offset))
4745 return TRUE;
4746 return is_clause_inside_range (nested, clause->try_offset, clause->try_offset + clause->try_len) ||
4747 is_clause_inside_range (nested, clause->handler_offset, clause->handler_offset + clause->handler_len);
4750 /* Test the relationship between 2 exception clauses. Follow P.1 12.4.2.7 of ECMA
4751 * the each pair of exception must have the following properties:
4752 * - one is fully nested on another (the outer must not be a filter clause) (the nested one must come earlier)
4753 * - completely disjoin (none of the 3 regions of each entry overlap with the other 3)
4754 * - mutual protection (protected block is EXACT the same, handlers are disjoin and all handler are catch or all handler are filter)
4756 static void
4757 verify_clause_relationship (VerifyContext *ctx, MonoExceptionClause *clause, MonoExceptionClause *to_test)
4759 /*clause is nested*/
4760 if (to_test->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (clause, to_test->data.filter_offset, to_test->handler_offset)) {
4761 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clause inside filter"));
4762 return;
4765 /*wrong nesting order.*/
4766 if (is_clause_nested (clause, to_test)) {
4767 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Nested exception clause appears after enclosing clause"));
4768 return;
4771 /*mutual protection*/
4772 if (clause->try_offset == to_test->try_offset && clause->try_len == to_test->try_len) {
4773 /*handlers are not disjoint*/
4774 if (is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) {
4775 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception handlers overlap"));
4776 return;
4778 /* handlers are not catch or filter */
4779 if (!IS_CATCH_OR_FILTER (clause) || !IS_CATCH_OR_FILTER (to_test)) {
4780 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses with shared protected block are neither catch or filter"));
4781 return;
4783 /*OK*/
4784 return;
4787 /*not completelly disjoint*/
4788 if ((is_clause_in_range (to_test, clause->try_offset, clause->try_offset + clause->try_len) ||
4789 is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) && !is_clause_nested (to_test, clause))
4790 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses overlap"));
4793 #define code_bounds_check(size) \
4794 if (ADDP_IS_GREATER_OR_OVF (ip, size, end)) {\
4795 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Code overrun starting with 0x%x at 0x%04x", *ip, ctx.ip_offset)); \
4796 break; \
4799 static gboolean
4800 mono_opcode_is_prefix (int op)
4802 switch (op) {
4803 case MONO_CEE_UNALIGNED_:
4804 case MONO_CEE_VOLATILE_:
4805 case MONO_CEE_TAIL_:
4806 case MONO_CEE_CONSTRAINED_:
4807 case MONO_CEE_READONLY_:
4808 return TRUE;
4810 return FALSE;
4814 * FIXME: need to distinguish between valid and verifiable.
4815 * Need to keep track of types on the stack.
4816 * Verify types for opcodes.
4818 GSList*
4819 mono_method_verify (MonoMethod *method, int level)
4821 MonoError error;
4822 const unsigned char *ip, *code_start;
4823 const unsigned char *end;
4824 MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
4826 int i, n, need_merge = 0, start = 0;
4827 guint ip_offset = 0, prefix = 0;
4828 MonoGenericContext *generic_context = NULL;
4829 MonoImage *image;
4830 VerifyContext ctx;
4831 GSList *tmp;
4832 VERIFIER_DEBUG ( printf ("Verify IL for method %s %s %s\n", method->klass->name_space, method->klass->name, method->name); );
4834 init_verifier_stats ();
4836 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
4837 (method->flags & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT))) {
4838 return NULL;
4841 memset (&ctx, 0, sizeof (VerifyContext));
4843 //FIXME use mono_method_get_signature_full
4844 ctx.signature = mono_method_signature (method);
4845 if (!ctx.signature) {
4846 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method signature"));
4848 finish_collect_stats ();
4849 return ctx.list;
4851 if (!method->is_generic && !mono_class_is_gtd (method->klass) && ctx.signature->has_type_parameters) {
4852 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Method and signature don't match in terms of genericity"));
4853 finish_collect_stats ();
4854 return ctx.list;
4857 ctx.header = mono_method_get_header_checked (method, &error);
4858 if (!ctx.header) {
4859 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method header due to %s", mono_error_get_message (&error)));
4860 mono_error_cleanup (&error);
4861 finish_collect_stats ();
4862 return ctx.list;
4864 ctx.method = method;
4865 code_start = ip = ctx.header->code;
4866 end = ip + ctx.header->code_size;
4867 ctx.image = image = method->klass->image;
4870 ctx.max_args = ctx.signature->param_count + ctx.signature->hasthis;
4871 ctx.max_stack = ctx.header->max_stack;
4872 ctx.verifiable = ctx.valid = 1;
4873 ctx.level = level;
4875 ctx.code = g_new (ILCodeDesc, ctx.header->code_size);
4876 ctx.code_size = ctx.header->code_size;
4877 _MEM_ALLOC (sizeof (ILCodeDesc) * ctx.header->code_size);
4879 memset(ctx.code, 0, sizeof (ILCodeDesc) * ctx.header->code_size);
4881 ctx.num_locals = ctx.header->num_locals;
4882 ctx.locals = (MonoType **)g_memdup (ctx.header->locals, sizeof (MonoType*) * ctx.header->num_locals);
4883 _MEM_ALLOC (sizeof (MonoType*) * ctx.header->num_locals);
4885 if (ctx.num_locals > 0 && !ctx.header->init_locals)
4886 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Method with locals variable but without init locals set"));
4888 ctx.params = g_new (MonoType*, ctx.max_args);
4889 _MEM_ALLOC (sizeof (MonoType*) * ctx.max_args);
4891 if (ctx.signature->hasthis)
4892 ctx.params [0] = method->klass->valuetype ? &method->klass->this_arg : &method->klass->byval_arg;
4893 memcpy (ctx.params + ctx.signature->hasthis, ctx.signature->params, sizeof (MonoType *) * ctx.signature->param_count);
4895 if (ctx.signature->is_inflated)
4896 ctx.generic_context = generic_context = mono_method_get_context (method);
4898 if (!generic_context && (mono_class_is_gtd (method->klass) || method->is_generic)) {
4899 if (method->is_generic)
4900 ctx.generic_context = generic_context = &(mono_method_get_generic_container (method)->context);
4901 else
4902 ctx.generic_context = generic_context = &mono_class_get_generic_container (method->klass)->context;
4905 for (i = 0; i < ctx.num_locals; ++i) {
4906 MonoType *uninflated = ctx.locals [i];
4907 ctx.locals [i] = mono_class_inflate_generic_type_checked (ctx.locals [i], ctx.generic_context, &error);
4908 if (!mono_error_ok (&error)) {
4909 char *name = mono_type_full_name (ctx.locals [i] ? ctx.locals [i] : uninflated);
4910 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %d of type %s", i, name));
4911 g_free (name);
4912 mono_error_cleanup (&error);
4913 /* we must not free (in cleanup) what was not yet allocated (but only copied) */
4914 ctx.num_locals = i;
4915 ctx.max_args = 0;
4916 goto cleanup;
4919 for (i = 0; i < ctx.max_args; ++i) {
4920 MonoType *uninflated = ctx.params [i];
4921 ctx.params [i] = mono_class_inflate_generic_type_checked (ctx.params [i], ctx.generic_context, &error);
4922 if (!mono_error_ok (&error)) {
4923 char *name = mono_type_full_name (ctx.params [i] ? ctx.params [i] : uninflated);
4924 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %d of type %s", i, name));
4925 g_free (name);
4926 mono_error_cleanup (&error);
4927 /* we must not free (in cleanup) what was not yet allocated (but only copied) */
4928 ctx.max_args = i;
4929 goto cleanup;
4932 stack_init (&ctx, &ctx.eval);
4934 for (i = 0; i < ctx.num_locals; ++i) {
4935 if (!mono_type_is_valid_in_context (&ctx, ctx.locals [i]))
4936 break;
4937 if (get_stack_type (ctx.locals [i]) == TYPE_INV) {
4938 char *name = mono_type_full_name (ctx.locals [i]);
4939 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %i of type %s", i, name));
4940 g_free (name);
4941 break;
4946 for (i = 0; i < ctx.max_args; ++i) {
4947 if (!mono_type_is_valid_in_context (&ctx, ctx.params [i]))
4948 break;
4950 if (get_stack_type (ctx.params [i]) == TYPE_INV) {
4951 char *name = mono_type_full_name (ctx.params [i]);
4952 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %i of type %s", i, name));
4953 g_free (name);
4954 break;
4958 if (!ctx.valid)
4959 goto cleanup;
4961 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
4962 MonoExceptionClause *clause = ctx.header->clauses + i;
4963 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); );
4965 if (clause->try_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, ctx.code_size))
4966 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause out of bounds at 0x%04x", clause->try_offset));
4968 if (clause->try_len <= 0)
4969 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause len <= 0 at 0x%04x", clause->try_offset));
4971 if (clause->handler_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->handler_offset, clause->handler_len, ctx.code_size))
4972 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause out of bounds at 0x%04x", clause->try_offset));
4974 if (clause->handler_len <= 0)
4975 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause len <= 0 at 0x%04x", clause->try_offset));
4977 if (clause->try_offset < clause->handler_offset && ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, HANDLER_START (clause)))
4978 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try block (at 0x%04x) includes handler block (at 0x%04x)", clause->try_offset, clause->handler_offset));
4980 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4981 if (clause->data.filter_offset > ctx.code_size)
4982 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause out of bounds at 0x%04x", clause->try_offset));
4984 if (clause->data.filter_offset >= clause->handler_offset)
4985 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause must come before the handler clause at 0x%04x", clause->data.filter_offset));
4988 for (n = i + 1; n < ctx.header->num_clauses && ctx.valid; ++n)
4989 verify_clause_relationship (&ctx, clause, ctx.header->clauses + n);
4991 if (!ctx.valid)
4992 break;
4994 ctx.code [clause->try_offset].flags |= IL_CODE_FLAG_WAS_TARGET;
4995 if (clause->try_offset + clause->try_len < ctx.code_size)
4996 ctx.code [clause->try_offset + clause->try_len].flags |= IL_CODE_FLAG_WAS_TARGET;
4997 if (clause->handler_offset + clause->handler_len < ctx.code_size)
4998 ctx.code [clause->handler_offset + clause->handler_len].flags |= IL_CODE_FLAG_WAS_TARGET;
5000 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
5001 if (!clause->data.catch_class) {
5002 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Catch clause %d with invalid type", i));
5003 break;
5005 if (!mono_type_is_valid_in_context (&ctx, &clause->data.catch_class->byval_arg))
5006 break;
5008 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, clause->data.catch_class);
5010 else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5011 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->data.filter_offset, mono_defaults.exception_class);
5012 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, mono_defaults.exception_class);
5016 if (!ctx.valid)
5017 goto cleanup;
5019 original_bb = bb = mono_basic_block_split (method, &error, ctx.header);
5020 if (!mono_error_ok (&error)) {
5021 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid branch target: %s", mono_error_get_message (&error)));
5022 mono_error_cleanup (&error);
5023 goto cleanup;
5025 g_assert (bb);
5027 while (ip < end && ctx.valid) {
5028 int op_size;
5029 ip_offset = (guint) (ip - code_start);
5031 const unsigned char *ip_copy = ip;
5032 int op;
5034 if (ip_offset > bb->end) {
5035 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block at [0x%04x] targets middle instruction at 0x%04x", bb->end, ip_offset));
5036 goto cleanup;
5039 if (ip_offset == bb->end)
5040 bb = bb->next;
5042 op_size = mono_opcode_value_and_size (&ip_copy, end, &op);
5043 if (op_size == -1) {
5044 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ip_offset));
5045 goto cleanup;
5048 if (ADD_IS_GREATER_OR_OVF (ip_offset, op_size, bb->end)) {
5049 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block targets middle of instruction at 0x%04x", ip_offset));
5050 goto cleanup;
5053 /*Last Instruction*/
5054 if (ip_offset + op_size == bb->end && mono_opcode_is_prefix (op)) {
5055 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));
5056 goto cleanup;
5060 ctx.ip_offset = ip_offset = (guint) (ip - code_start);
5062 /*We need to check against fallthrou in and out of protected blocks.
5063 * For fallout we check the once a protected block ends, if the start flag is not set.
5064 * Likewise for fallthru in, we check if ip is the start of a protected block and start is not set
5065 * TODO convert these checks to be done using flags and not this loop
5067 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
5068 MonoExceptionClause *clause = ctx.header->clauses + i;
5070 if ((clause->try_offset + clause->try_len == ip_offset) && start == 0) {
5071 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru off try block at 0x%04x", ip_offset));
5072 start = 1;
5075 if ((clause->handler_offset + clause->handler_len == ip_offset) && start == 0) {
5076 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
5077 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
5078 else
5079 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
5080 start = 1;
5083 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && clause->handler_offset == ip_offset && start == 0) {
5084 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of filter block at 0x%04x", ip_offset));
5085 start = 1;
5088 if (clause->handler_offset == ip_offset && start == 0) {
5089 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru handler block at 0x%04x", ip_offset));
5090 start = 1;
5093 if (clause->try_offset == ip_offset && ctx.eval.size > 0 && start == 0) {
5094 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Try to enter try block with a non-empty stack at 0x%04x", ip_offset));
5095 start = 1;
5099 /*This must be done after fallthru detection otherwise it won't happen.*/
5100 if (bb->dead) {
5101 /*FIXME remove this once we move all bad branch checking code to use BB only*/
5102 ctx.code [ip_offset].flags |= IL_CODE_FLAG_SEEN;
5103 ip += op_size;
5104 continue;
5107 if (!ctx.valid)
5108 break;
5110 if (need_merge) {
5111 VERIFIER_DEBUG ( printf ("extra merge needed! 0x%04x \n", ctx.target); );
5112 merge_stacks (&ctx, &ctx.eval, &ctx.code [ctx.target], FALSE, TRUE);
5113 need_merge = 0;
5115 merge_stacks (&ctx, &ctx.eval, &ctx.code[ip_offset], start, FALSE);
5116 start = 0;
5118 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
5119 #ifdef MONO_VERIFIER_DEBUG
5121 char *discode;
5122 discode = mono_disasm_code_one (NULL, method, ip, NULL);
5123 discode [strlen (discode) - 1] = 0; /* no \n */
5124 g_print ("[%d] %-29s (%d)\n", ip_offset, discode, ctx.eval.size);
5125 g_free (discode);
5127 dump_stack_state (&ctx.code [ip_offset]);
5128 dump_stack_state (&ctx.eval);
5129 #endif
5131 switch (*ip) {
5132 case CEE_NOP:
5133 case CEE_BREAK:
5134 ++ip;
5135 break;
5137 case CEE_LDARG_0:
5138 case CEE_LDARG_1:
5139 case CEE_LDARG_2:
5140 case CEE_LDARG_3:
5141 push_arg (&ctx, *ip - CEE_LDARG_0, FALSE);
5142 ++ip;
5143 break;
5145 case CEE_LDARG_S:
5146 case CEE_LDARGA_S:
5147 code_bounds_check (2);
5148 push_arg (&ctx, ip [1], *ip == CEE_LDARGA_S);
5149 ip += 2;
5150 break;
5152 case CEE_ADD_OVF_UN:
5153 do_binop (&ctx, *ip, add_ovf_un_table);
5154 ++ip;
5155 break;
5157 case CEE_SUB_OVF_UN:
5158 do_binop (&ctx, *ip, sub_ovf_un_table);
5159 ++ip;
5160 break;
5162 case CEE_ADD_OVF:
5163 case CEE_SUB_OVF:
5164 case CEE_MUL_OVF:
5165 case CEE_MUL_OVF_UN:
5166 do_binop (&ctx, *ip, bin_ovf_table);
5167 ++ip;
5168 break;
5170 case CEE_ADD:
5171 do_binop (&ctx, *ip, add_table);
5172 ++ip;
5173 break;
5175 case CEE_SUB:
5176 do_binop (&ctx, *ip, sub_table);
5177 ++ip;
5178 break;
5180 case CEE_MUL:
5181 case CEE_DIV:
5182 case CEE_REM:
5183 do_binop (&ctx, *ip, bin_op_table);
5184 ++ip;
5185 break;
5187 case CEE_AND:
5188 case CEE_DIV_UN:
5189 case CEE_OR:
5190 case CEE_REM_UN:
5191 case CEE_XOR:
5192 do_binop (&ctx, *ip, int_bin_op_table);
5193 ++ip;
5194 break;
5196 case CEE_SHL:
5197 case CEE_SHR:
5198 case CEE_SHR_UN:
5199 do_binop (&ctx, *ip, shift_op_table);
5200 ++ip;
5201 break;
5203 case CEE_POP:
5204 if (!check_underflow (&ctx, 1))
5205 break;
5206 stack_pop_safe (&ctx);
5207 ++ip;
5208 break;
5210 case CEE_RET:
5211 do_ret (&ctx);
5212 ++ip;
5213 start = 1;
5214 break;
5216 case CEE_LDLOC_0:
5217 case CEE_LDLOC_1:
5218 case CEE_LDLOC_2:
5219 case CEE_LDLOC_3:
5220 /*TODO support definite assignment verification? */
5221 push_local (&ctx, *ip - CEE_LDLOC_0, FALSE);
5222 ++ip;
5223 break;
5225 case CEE_STLOC_0:
5226 case CEE_STLOC_1:
5227 case CEE_STLOC_2:
5228 case CEE_STLOC_3:
5229 store_local (&ctx, *ip - CEE_STLOC_0);
5230 ++ip;
5231 break;
5233 case CEE_STLOC_S:
5234 code_bounds_check (2);
5235 store_local (&ctx, ip [1]);
5236 ip += 2;
5237 break;
5239 case CEE_STARG_S:
5240 code_bounds_check (2);
5241 store_arg (&ctx, ip [1]);
5242 ip += 2;
5243 break;
5245 case CEE_LDC_I4_M1:
5246 case CEE_LDC_I4_0:
5247 case CEE_LDC_I4_1:
5248 case CEE_LDC_I4_2:
5249 case CEE_LDC_I4_3:
5250 case CEE_LDC_I4_4:
5251 case CEE_LDC_I4_5:
5252 case CEE_LDC_I4_6:
5253 case CEE_LDC_I4_7:
5254 case CEE_LDC_I4_8:
5255 if (check_overflow (&ctx))
5256 stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
5257 ++ip;
5258 break;
5260 case CEE_LDC_I4_S:
5261 code_bounds_check (2);
5262 if (check_overflow (&ctx))
5263 stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
5264 ip += 2;
5265 break;
5267 case CEE_LDC_I4:
5268 code_bounds_check (5);
5269 if (check_overflow (&ctx))
5270 stack_push_val (&ctx,TYPE_I4, &mono_defaults.int32_class->byval_arg);
5271 ip += 5;
5272 break;
5274 case CEE_LDC_I8:
5275 code_bounds_check (9);
5276 if (check_overflow (&ctx))
5277 stack_push_val (&ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
5278 ip += 9;
5279 break;
5281 case CEE_LDC_R4:
5282 code_bounds_check (5);
5283 if (check_overflow (&ctx))
5284 stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
5285 ip += 5;
5286 break;
5288 case CEE_LDC_R8:
5289 code_bounds_check (9);
5290 if (check_overflow (&ctx))
5291 stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
5292 ip += 9;
5293 break;
5295 case CEE_LDNULL:
5296 if (check_overflow (&ctx))
5297 stack_push_val (&ctx, TYPE_COMPLEX | NULL_LITERAL_MASK, &mono_defaults.object_class->byval_arg);
5298 ++ip;
5299 break;
5301 case CEE_BEQ_S:
5302 case CEE_BNE_UN_S:
5303 code_bounds_check (2);
5304 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_eq_op);
5305 ip += 2;
5306 need_merge = 1;
5307 break;
5309 case CEE_BGE_S:
5310 case CEE_BGT_S:
5311 case CEE_BLE_S:
5312 case CEE_BLT_S:
5313 case CEE_BGE_UN_S:
5314 case CEE_BGT_UN_S:
5315 case CEE_BLE_UN_S:
5316 case CEE_BLT_UN_S:
5317 code_bounds_check (2);
5318 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_op);
5319 ip += 2;
5320 need_merge = 1;
5321 break;
5323 case CEE_BEQ:
5324 case CEE_BNE_UN:
5325 code_bounds_check (5);
5326 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_eq_op);
5327 ip += 5;
5328 need_merge = 1;
5329 break;
5331 case CEE_BGE:
5332 case CEE_BGT:
5333 case CEE_BLE:
5334 case CEE_BLT:
5335 case CEE_BGE_UN:
5336 case CEE_BGT_UN:
5337 case CEE_BLE_UN:
5338 case CEE_BLT_UN:
5339 code_bounds_check (5);
5340 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_op);
5341 ip += 5;
5342 need_merge = 1;
5343 break;
5345 case CEE_LDLOC_S:
5346 case CEE_LDLOCA_S:
5347 code_bounds_check (2);
5348 push_local (&ctx, ip[1], *ip == CEE_LDLOCA_S);
5349 ip += 2;
5350 break;
5352 case CEE_UNUSED99:
5353 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5354 ++ip;
5355 break;
5357 case CEE_DUP: {
5358 ILStackDesc *top;
5359 if (!check_underflow (&ctx, 1))
5360 break;
5361 if (!check_overflow (&ctx))
5362 break;
5363 top = stack_push (&ctx);
5364 copy_stack_value (top, stack_peek (&ctx, 1));
5365 ++ip;
5366 break;
5369 case CEE_JMP:
5370 code_bounds_check (5);
5371 if (ctx.eval.size)
5372 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Eval stack must be empty in jmp at 0x%04x", ip_offset));
5373 /* token = read32 (ip + 1); */
5374 if (in_any_block (ctx.header, ip_offset))
5375 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("jmp cannot escape exception blocks at 0x%04x", ip_offset));
5377 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction jmp is not verifiable at 0x%04x", ctx.ip_offset));
5379 * FIXME: check signature, retval, arguments etc.
5381 ip += 5;
5382 break;
5383 case CEE_CALL:
5384 case CEE_CALLVIRT:
5385 code_bounds_check (5);
5386 do_invoke_method (&ctx, read32 (ip + 1), *ip == CEE_CALLVIRT);
5387 ip += 5;
5388 break;
5390 case CEE_CALLI:
5391 code_bounds_check (5);
5392 /* token = read32 (ip + 1); */
5394 * FIXME: check signature, retval, arguments etc.
5395 * FIXME: check requirements for tail call
5397 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction calli is not verifiable at 0x%04x", ctx.ip_offset));
5398 ip += 5;
5399 break;
5400 case CEE_BR_S:
5401 code_bounds_check (2);
5402 do_static_branch (&ctx, (signed char)ip [1] + 2);
5403 need_merge = 1;
5404 ip += 2;
5405 start = 1;
5406 break;
5408 case CEE_BRFALSE_S:
5409 case CEE_BRTRUE_S:
5410 code_bounds_check (2);
5411 do_boolean_branch_op (&ctx, (signed char)ip [1] + 2);
5412 ip += 2;
5413 need_merge = 1;
5414 break;
5416 case CEE_BR:
5417 code_bounds_check (5);
5418 do_static_branch (&ctx, (gint32)read32 (ip + 1) + 5);
5419 need_merge = 1;
5420 ip += 5;
5421 start = 1;
5422 break;
5424 case CEE_BRFALSE:
5425 case CEE_BRTRUE:
5426 code_bounds_check (5);
5427 do_boolean_branch_op (&ctx, (gint32)read32 (ip + 1) + 5);
5428 ip += 5;
5429 need_merge = 1;
5430 break;
5432 case CEE_SWITCH: {
5433 guint32 entries;
5434 code_bounds_check (5);
5435 entries = read32 (ip + 1);
5437 if (entries > 0xFFFFFFFFU / sizeof (guint32))
5438 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Too many switch entries %x at 0x%04x", entries, ctx.ip_offset));
5440 ip += 5;
5441 code_bounds_check (sizeof (guint32) * entries);
5443 do_switch (&ctx, entries, ip);
5444 ip += sizeof (guint32) * entries;
5445 break;
5447 case CEE_LDIND_I1:
5448 case CEE_LDIND_U1:
5449 case CEE_LDIND_I2:
5450 case CEE_LDIND_U2:
5451 case CEE_LDIND_I4:
5452 case CEE_LDIND_U4:
5453 case CEE_LDIND_I8:
5454 case CEE_LDIND_I:
5455 case CEE_LDIND_R4:
5456 case CEE_LDIND_R8:
5457 case CEE_LDIND_REF:
5458 do_load_indirect (&ctx, *ip);
5459 ++ip;
5460 break;
5462 case CEE_STIND_REF:
5463 case CEE_STIND_I1:
5464 case CEE_STIND_I2:
5465 case CEE_STIND_I4:
5466 case CEE_STIND_I8:
5467 case CEE_STIND_R4:
5468 case CEE_STIND_R8:
5469 case CEE_STIND_I:
5470 do_store_indirect (&ctx, *ip);
5471 ++ip;
5472 break;
5474 case CEE_NOT:
5475 case CEE_NEG:
5476 do_unary_math_op (&ctx, *ip);
5477 ++ip;
5478 break;
5480 case CEE_CONV_I1:
5481 case CEE_CONV_I2:
5482 case CEE_CONV_I4:
5483 case CEE_CONV_U1:
5484 case CEE_CONV_U2:
5485 case CEE_CONV_U4:
5486 do_conversion (&ctx, TYPE_I4);
5487 ++ip;
5488 break;
5490 case CEE_CONV_I8:
5491 case CEE_CONV_U8:
5492 do_conversion (&ctx, TYPE_I8);
5493 ++ip;
5494 break;
5496 case CEE_CONV_R4:
5497 case CEE_CONV_R8:
5498 case CEE_CONV_R_UN:
5499 do_conversion (&ctx, TYPE_R8);
5500 ++ip;
5501 break;
5503 case CEE_CONV_I:
5504 case CEE_CONV_U:
5505 do_conversion (&ctx, TYPE_NATIVE_INT);
5506 ++ip;
5507 break;
5509 case CEE_CPOBJ:
5510 code_bounds_check (5);
5511 do_cpobj (&ctx, read32 (ip + 1));
5512 ip += 5;
5513 break;
5515 case CEE_LDOBJ:
5516 code_bounds_check (5);
5517 do_ldobj_value (&ctx, read32 (ip + 1));
5518 ip += 5;
5519 break;
5521 case CEE_LDSTR:
5522 code_bounds_check (5);
5523 do_ldstr (&ctx, read32 (ip + 1));
5524 ip += 5;
5525 break;
5527 case CEE_NEWOBJ:
5528 code_bounds_check (5);
5529 do_newobj (&ctx, read32 (ip + 1));
5530 ip += 5;
5531 break;
5533 case CEE_CASTCLASS:
5534 case CEE_ISINST:
5535 code_bounds_check (5);
5536 do_cast (&ctx, read32 (ip + 1), *ip == CEE_CASTCLASS ? "castclass" : "isinst");
5537 ip += 5;
5538 break;
5540 case CEE_UNUSED58:
5541 case CEE_UNUSED1:
5542 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5543 ++ip;
5544 break;
5546 case CEE_UNBOX:
5547 code_bounds_check (5);
5548 do_unbox_value (&ctx, read32 (ip + 1));
5549 ip += 5;
5550 break;
5552 case CEE_THROW:
5553 do_throw (&ctx);
5554 start = 1;
5555 ++ip;
5556 break;
5558 case CEE_LDFLD:
5559 case CEE_LDFLDA:
5560 code_bounds_check (5);
5561 do_push_field (&ctx, read32 (ip + 1), *ip == CEE_LDFLDA);
5562 ip += 5;
5563 break;
5565 case CEE_LDSFLD:
5566 case CEE_LDSFLDA:
5567 code_bounds_check (5);
5568 do_push_static_field (&ctx, read32 (ip + 1), *ip == CEE_LDSFLDA);
5569 ip += 5;
5570 break;
5572 case CEE_STFLD:
5573 code_bounds_check (5);
5574 do_store_field (&ctx, read32 (ip + 1));
5575 ip += 5;
5576 break;
5578 case CEE_STSFLD:
5579 code_bounds_check (5);
5580 do_store_static_field (&ctx, read32 (ip + 1));
5581 ip += 5;
5582 break;
5584 case CEE_STOBJ:
5585 code_bounds_check (5);
5586 do_stobj (&ctx, read32 (ip + 1));
5587 ip += 5;
5588 break;
5590 case CEE_CONV_OVF_I1_UN:
5591 case CEE_CONV_OVF_I2_UN:
5592 case CEE_CONV_OVF_I4_UN:
5593 case CEE_CONV_OVF_U1_UN:
5594 case CEE_CONV_OVF_U2_UN:
5595 case CEE_CONV_OVF_U4_UN:
5596 do_conversion (&ctx, TYPE_I4);
5597 ++ip;
5598 break;
5600 case CEE_CONV_OVF_I8_UN:
5601 case CEE_CONV_OVF_U8_UN:
5602 do_conversion (&ctx, TYPE_I8);
5603 ++ip;
5604 break;
5606 case CEE_CONV_OVF_I_UN:
5607 case CEE_CONV_OVF_U_UN:
5608 do_conversion (&ctx, TYPE_NATIVE_INT);
5609 ++ip;
5610 break;
5612 case CEE_BOX:
5613 code_bounds_check (5);
5614 do_box_value (&ctx, read32 (ip + 1));
5615 ip += 5;
5616 break;
5618 case CEE_NEWARR:
5619 code_bounds_check (5);
5620 do_newarr (&ctx, read32 (ip + 1));
5621 ip += 5;
5622 break;
5624 case CEE_LDLEN:
5625 do_ldlen (&ctx);
5626 ++ip;
5627 break;
5629 case CEE_LDELEMA:
5630 code_bounds_check (5);
5631 do_ldelema (&ctx, read32 (ip + 1));
5632 ip += 5;
5633 break;
5635 case CEE_LDELEM_I1:
5636 case CEE_LDELEM_U1:
5637 case CEE_LDELEM_I2:
5638 case CEE_LDELEM_U2:
5639 case CEE_LDELEM_I4:
5640 case CEE_LDELEM_U4:
5641 case CEE_LDELEM_I8:
5642 case CEE_LDELEM_I:
5643 case CEE_LDELEM_R4:
5644 case CEE_LDELEM_R8:
5645 case CEE_LDELEM_REF:
5646 do_ldelem (&ctx, *ip, 0);
5647 ++ip;
5648 break;
5650 case CEE_STELEM_I:
5651 case CEE_STELEM_I1:
5652 case CEE_STELEM_I2:
5653 case CEE_STELEM_I4:
5654 case CEE_STELEM_I8:
5655 case CEE_STELEM_R4:
5656 case CEE_STELEM_R8:
5657 case CEE_STELEM_REF:
5658 do_stelem (&ctx, *ip, 0);
5659 ++ip;
5660 break;
5662 case CEE_LDELEM:
5663 code_bounds_check (5);
5664 do_ldelem (&ctx, *ip, read32 (ip + 1));
5665 ip += 5;
5666 break;
5668 case CEE_STELEM:
5669 code_bounds_check (5);
5670 do_stelem (&ctx, *ip, read32 (ip + 1));
5671 ip += 5;
5672 break;
5674 case CEE_UNBOX_ANY:
5675 code_bounds_check (5);
5676 do_unbox_any (&ctx, read32 (ip + 1));
5677 ip += 5;
5678 break;
5680 case CEE_CONV_OVF_I1:
5681 case CEE_CONV_OVF_U1:
5682 case CEE_CONV_OVF_I2:
5683 case CEE_CONV_OVF_U2:
5684 case CEE_CONV_OVF_I4:
5685 case CEE_CONV_OVF_U4:
5686 do_conversion (&ctx, TYPE_I4);
5687 ++ip;
5688 break;
5690 case CEE_CONV_OVF_I8:
5691 case CEE_CONV_OVF_U8:
5692 do_conversion (&ctx, TYPE_I8);
5693 ++ip;
5694 break;
5696 case CEE_CONV_OVF_I:
5697 case CEE_CONV_OVF_U:
5698 do_conversion (&ctx, TYPE_NATIVE_INT);
5699 ++ip;
5700 break;
5702 case CEE_REFANYVAL:
5703 code_bounds_check (5);
5704 do_refanyval (&ctx, read32 (ip + 1));
5705 ip += 5;
5706 break;
5708 case CEE_CKFINITE:
5709 do_ckfinite (&ctx);
5710 ++ip;
5711 break;
5713 case CEE_MKREFANY:
5714 code_bounds_check (5);
5715 do_mkrefany (&ctx, read32 (ip + 1));
5716 ip += 5;
5717 break;
5719 case CEE_LDTOKEN:
5720 code_bounds_check (5);
5721 do_load_token (&ctx, read32 (ip + 1));
5722 ip += 5;
5723 break;
5725 case CEE_ENDFINALLY:
5726 if (!is_correct_endfinally (ctx.header, ip_offset))
5727 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("endfinally must be used inside a finally/fault handler at 0x%04x", ctx.ip_offset));
5728 ctx.eval.size = 0;
5729 start = 1;
5730 ++ip;
5731 break;
5733 case CEE_LEAVE:
5734 code_bounds_check (5);
5735 do_leave (&ctx, read32 (ip + 1) + 5);
5736 ip += 5;
5737 start = 1;
5738 need_merge = 1;
5739 break;
5741 case CEE_LEAVE_S:
5742 code_bounds_check (2);
5743 do_leave (&ctx, (signed char)ip [1] + 2);
5744 ip += 2;
5745 start = 1;
5746 need_merge = 1;
5747 break;
5749 case CEE_PREFIX1:
5750 code_bounds_check (2);
5751 ++ip;
5752 switch (*ip) {
5753 case CEE_STLOC:
5754 code_bounds_check (3);
5755 store_local (&ctx, read16 (ip + 1));
5756 ip += 3;
5757 break;
5759 case CEE_CEQ:
5760 do_cmp_op (&ctx, cmp_br_eq_op, *ip);
5761 ++ip;
5762 break;
5764 case CEE_CGT:
5765 case CEE_CGT_UN:
5766 case CEE_CLT:
5767 case CEE_CLT_UN:
5768 do_cmp_op (&ctx, cmp_br_op, *ip);
5769 ++ip;
5770 break;
5772 case CEE_STARG:
5773 code_bounds_check (3);
5774 store_arg (&ctx, read16 (ip + 1) );
5775 ip += 3;
5776 break;
5779 case CEE_ARGLIST:
5780 if (!check_overflow (&ctx))
5781 break;
5782 if (ctx.signature->call_convention != MONO_CALL_VARARG)
5783 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot use arglist on method without VARGARG calling convention at 0x%04x", ctx.ip_offset));
5784 set_stack_value (&ctx, stack_push (&ctx), &mono_defaults.argumenthandle_class->byval_arg, FALSE);
5785 ++ip;
5786 break;
5788 case CEE_LDFTN:
5789 code_bounds_check (5);
5790 do_load_function_ptr (&ctx, read32 (ip + 1), FALSE);
5791 ip += 5;
5792 break;
5794 case CEE_LDVIRTFTN:
5795 code_bounds_check (5);
5796 do_load_function_ptr (&ctx, read32 (ip + 1), TRUE);
5797 ip += 5;
5798 break;
5800 case CEE_LDARG:
5801 case CEE_LDARGA:
5802 code_bounds_check (3);
5803 push_arg (&ctx, read16 (ip + 1), *ip == CEE_LDARGA);
5804 ip += 3;
5805 break;
5807 case CEE_LDLOC:
5808 case CEE_LDLOCA:
5809 code_bounds_check (3);
5810 push_local (&ctx, read16 (ip + 1), *ip == CEE_LDLOCA);
5811 ip += 3;
5812 break;
5814 case CEE_LOCALLOC:
5815 do_localloc (&ctx);
5816 ++ip;
5817 break;
5819 case CEE_UNUSED56:
5820 case CEE_UNUSED57:
5821 case CEE_UNUSED70:
5822 case CEE_UNUSED:
5823 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5824 ++ip;
5825 break;
5826 case CEE_ENDFILTER:
5827 do_endfilter (&ctx);
5828 start = 1;
5829 ++ip;
5830 break;
5831 case CEE_UNALIGNED_:
5832 code_bounds_check (2);
5833 prefix |= PREFIX_UNALIGNED;
5834 ip += 2;
5835 break;
5836 case CEE_VOLATILE_:
5837 prefix |= PREFIX_VOLATILE;
5838 ++ip;
5839 break;
5840 case CEE_TAIL_:
5841 prefix |= PREFIX_TAIL;
5842 ++ip;
5843 if (ip < end && (*ip != CEE_CALL && *ip != CEE_CALLI && *ip != CEE_CALLVIRT))
5844 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("tail prefix must be used only with call opcodes at 0x%04x", ip_offset));
5845 break;
5847 case CEE_INITOBJ:
5848 code_bounds_check (5);
5849 do_initobj (&ctx, read32 (ip + 1));
5850 ip += 5;
5851 break;
5853 case CEE_CONSTRAINED_:
5854 code_bounds_check (5);
5855 ctx.constrained_type = get_boxable_mono_type (&ctx, read32 (ip + 1), "constrained.");
5856 prefix |= PREFIX_CONSTRAINED;
5857 ip += 5;
5858 break;
5860 case CEE_READONLY_:
5861 prefix |= PREFIX_READONLY;
5862 ip++;
5863 break;
5865 case CEE_CPBLK:
5866 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5867 if (!check_underflow (&ctx, 3))
5868 break;
5869 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction cpblk is not verifiable at 0x%04x", ctx.ip_offset));
5870 ip++;
5871 break;
5873 case CEE_INITBLK:
5874 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5875 if (!check_underflow (&ctx, 3))
5876 break;
5877 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction initblk is not verifiable at 0x%04x", ctx.ip_offset));
5878 ip++;
5879 break;
5881 case CEE_NO_:
5882 ip += 2;
5883 break;
5884 case CEE_RETHROW:
5885 if (!is_correct_rethrow (ctx.header, ip_offset))
5886 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("rethrow must be used inside a catch handler at 0x%04x", ctx.ip_offset));
5887 ctx.eval.size = 0;
5888 start = 1;
5889 ++ip;
5890 break;
5892 case CEE_SIZEOF:
5893 code_bounds_check (5);
5894 do_sizeof (&ctx, read32 (ip + 1));
5895 ip += 5;
5896 break;
5898 case CEE_REFANYTYPE:
5899 do_refanytype (&ctx);
5900 ++ip;
5901 break;
5903 default:
5904 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction FE %x at 0x%04x", *ip, ctx.ip_offset));
5905 ++ip;
5907 break;
5909 default:
5910 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ctx.ip_offset));
5911 ++ip;
5914 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
5915 if (prefix) {
5916 if (!ctx.prefix_set) //first prefix
5917 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
5918 ctx.prefix_set |= prefix;
5919 ctx.has_flags = TRUE;
5920 prefix = 0;
5921 } else {
5922 if (!ctx.has_flags)
5923 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
5925 if (ctx.prefix_set & PREFIX_CONSTRAINED)
5926 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after constrained prefix at 0x%04x", ctx.ip_offset));
5927 if (ctx.prefix_set & PREFIX_READONLY)
5928 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after readonly prefix at 0x%04x", ctx.ip_offset));
5929 if (ctx.prefix_set & PREFIX_VOLATILE)
5930 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after volatile prefix at 0x%04x", ctx.ip_offset));
5931 if (ctx.prefix_set & PREFIX_UNALIGNED)
5932 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after unaligned prefix at 0x%04x", ctx.ip_offset));
5933 ctx.prefix_set = prefix = 0;
5934 ctx.has_flags = FALSE;
5938 * if ip != end we overflowed: mark as error.
5940 if ((ip != end || !start) && ctx.verifiable && !ctx.list) {
5941 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Run ahead of method code at 0x%04x", ip_offset));
5944 /*We should guard against the last decoded opcode, otherwise we might add errors that doesn't make sense.*/
5945 for (i = 0; i < ctx.code_size && i < ip_offset; ++i) {
5946 if (ctx.code [i].flags & IL_CODE_FLAG_WAS_TARGET) {
5947 if (!(ctx.code [i].flags & IL_CODE_FLAG_SEEN))
5948 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or exception block target middle of intruction at 0x%04x", i));
5950 if (ctx.code [i].flags & IL_CODE_DELEGATE_SEQUENCE)
5951 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Branch to delegate code sequence at 0x%04x", i));
5953 if ((ctx.code [i].flags & IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL) && ctx.has_this_store)
5954 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at 0x%04x", i));
5956 if ((ctx.code [i].flags & IL_CODE_CALL_NONFINAL_VIRTUAL) && ctx.has_this_store)
5957 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));
5960 if (mono_method_is_constructor (ctx.method) && !ctx.super_ctor_called && !ctx.method->klass->valuetype && ctx.method->klass != mono_defaults.object_class) {
5961 char *method_name = mono_method_full_name (ctx.method, TRUE);
5962 char *type = mono_type_get_full_name (ctx.method->klass);
5963 if (ctx.method->klass->parent && mono_class_has_failure (ctx.method->klass->parent))
5964 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));
5965 else
5966 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Constructor %s for type %s not calling base type ctor.", method_name, type));
5967 g_free (method_name);
5968 g_free (type);
5971 cleanup:
5972 if (ctx.code) {
5973 for (i = 0; i < ctx.header->code_size; ++i) {
5974 if (ctx.code [i].stack)
5975 g_free (ctx.code [i].stack);
5979 for (tmp = ctx.funptrs; tmp; tmp = tmp->next)
5980 g_free (tmp->data);
5981 g_slist_free (ctx.funptrs);
5983 for (tmp = ctx.exception_types; tmp; tmp = tmp->next)
5984 mono_metadata_free_type ((MonoType *)tmp->data);
5985 g_slist_free (ctx.exception_types);
5987 for (i = 0; i < ctx.num_locals; ++i) {
5988 if (ctx.locals [i])
5989 mono_metadata_free_type (ctx.locals [i]);
5991 for (i = 0; i < ctx.max_args; ++i) {
5992 if (ctx.params [i])
5993 mono_metadata_free_type (ctx.params [i]);
5996 if (ctx.eval.stack)
5997 g_free (ctx.eval.stack);
5998 if (ctx.code)
5999 g_free (ctx.code);
6000 g_free (ctx.locals);
6001 g_free (ctx.params);
6002 mono_basic_block_free (original_bb);
6003 mono_metadata_free_mh (ctx.header);
6005 finish_collect_stats ();
6006 return ctx.list;
6009 char*
6010 mono_verify_corlib ()
6012 /* This is a public API function so cannot be removed */
6013 return NULL;
6017 * mono_verifier_is_enabled_for_method:
6018 * @method: the method to probe
6020 * Returns TRUE if @method needs to be verified.
6023 gboolean
6024 mono_verifier_is_enabled_for_method (MonoMethod *method)
6026 return mono_verifier_is_enabled_for_class (method->klass) && (method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD);
6030 * mono_verifier_is_enabled_for_class:
6031 * @klass: The `MonoClass` to probe
6033 * Returns TRUE if @klass need to be verified.
6036 gboolean
6037 mono_verifier_is_enabled_for_class (MonoClass *klass)
6039 return verify_all || (verifier_mode > MONO_VERIFIER_MODE_OFF && !(klass->image->assembly && klass->image->assembly->in_gac) && klass->image != mono_defaults.corlib);
6042 gboolean
6043 mono_verifier_is_enabled_for_image (MonoImage *image)
6045 return verify_all || verifier_mode > MONO_VERIFIER_MODE_OFF;
6049 * Dynamic methods are not considered full trust since if the user is trusted and need to
6050 * generate unsafe code, make the method skip verification - this is a known good way to do it.
6052 gboolean
6053 mono_verifier_is_method_full_trust (MonoMethod *method)
6055 return mono_verifier_is_class_full_trust (method->klass) && !method_is_dynamic (method);
6059 * Returns if @klass is under full trust or not.
6061 * TODO This code doesn't take CAS into account.
6063 * Under verify_all all user code must be verifiable if no security option was set
6066 gboolean
6067 mono_verifier_is_class_full_trust (MonoClass *klass)
6069 /* under CoreCLR code is trusted if it is part of the "platform" otherwise all code inside the GAC is trusted */
6070 gboolean trusted_location = !mono_security_core_clr_enabled () ?
6071 (klass->image->assembly && klass->image->assembly->in_gac) : mono_security_core_clr_is_platform_image (klass->image);
6073 if (verify_all && verifier_mode == MONO_VERIFIER_MODE_OFF)
6074 return trusted_location || klass->image == mono_defaults.corlib;
6075 return verifier_mode < MONO_VERIFIER_MODE_VERIFIABLE || trusted_location || klass->image == mono_defaults.corlib;
6078 GSList*
6079 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility, gboolean is_fulltrust)
6081 return mono_method_verify (method,
6082 (verifier_mode != MONO_VERIFIER_MODE_STRICT ? MONO_VERIFY_NON_STRICT: 0)
6083 | (!is_fulltrust && !mono_verifier_is_method_full_trust (method) ? MONO_VERIFY_FAIL_FAST : 0)
6084 | (skip_visibility ? MONO_VERIFY_SKIP_VISIBILITY : 0));
6087 static int
6088 get_field_end (MonoClassField *field)
6090 int align;
6091 int size = mono_type_size (field->type, &align);
6092 if (size == 0)
6093 size = 4; /*FIXME Is this a safe bet?*/
6094 return size + field->offset;
6097 static gboolean
6098 verify_class_for_overlapping_reference_fields (MonoClass *klass)
6100 int i = 0, j;
6101 gpointer iter = NULL;
6102 MonoClassField *field;
6103 gboolean is_fulltrust = mono_verifier_is_class_full_trust (klass);
6104 /*We can't skip types with !has_references since this is calculated after we have run.*/
6105 if (!mono_class_is_explicit_layout (klass))
6106 return TRUE;
6109 /*We must check for stuff overlapping reference fields.
6110 The outer loop uses mono_class_get_fields to ensure that MonoClass:fields get inited.
6112 while ((field = mono_class_get_fields (klass, &iter))) {
6113 int fieldEnd = get_field_end (field);
6114 gboolean is_valuetype = !MONO_TYPE_IS_REFERENCE (field->type);
6115 ++i;
6117 if (mono_field_is_deleted (field) || (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
6118 continue;
6120 int fcount = mono_class_get_field_count (klass);
6121 for (j = i; j < fcount; ++j) {
6122 MonoClassField *other = &klass->fields [j];
6123 int otherEnd = get_field_end (other);
6124 if (mono_field_is_deleted (other) || (is_valuetype && !MONO_TYPE_IS_REFERENCE (other->type)) || (other->type->attrs & FIELD_ATTRIBUTE_STATIC))
6125 continue;
6127 if (!is_valuetype && MONO_TYPE_IS_REFERENCE (other->type) && field->offset == other->offset && is_fulltrust)
6128 continue;
6130 if ((otherEnd > field->offset && otherEnd <= fieldEnd) || (other->offset >= field->offset && other->offset < fieldEnd))
6131 return FALSE;
6134 return TRUE;
6137 static guint
6138 field_hash (gconstpointer key)
6140 const MonoClassField *field = (const MonoClassField *)key;
6141 return g_str_hash (field->name) ^ mono_metadata_type_hash (field->type); /**/
6144 static gboolean
6145 field_equals (gconstpointer _a, gconstpointer _b)
6147 const MonoClassField *a = (const MonoClassField *)_a;
6148 const MonoClassField *b = (const MonoClassField *)_b;
6149 return !strcmp (a->name, b->name) && mono_metadata_type_equal (a->type, b->type);
6153 static gboolean
6154 verify_class_fields (MonoClass *klass)
6156 gpointer iter = NULL;
6157 MonoClassField *field;
6158 MonoGenericContext *context = mono_class_get_context (klass);
6159 GHashTable *unique_fields = g_hash_table_new_full (&field_hash, &field_equals, NULL, NULL);
6160 if (mono_class_is_gtd (klass))
6161 context = &mono_class_get_generic_container (klass)->context;
6163 while ((field = mono_class_get_fields (klass, &iter)) != NULL) {
6164 if (!mono_type_is_valid_type_in_context (field->type, context)) {
6165 g_hash_table_destroy (unique_fields);
6166 return FALSE;
6168 if (g_hash_table_lookup (unique_fields, field)) {
6169 g_hash_table_destroy (unique_fields);
6170 return FALSE;
6172 g_hash_table_insert (unique_fields, field, field);
6174 g_hash_table_destroy (unique_fields);
6175 return TRUE;
6178 static gboolean
6179 verify_interfaces (MonoClass *klass)
6181 int i;
6182 for (i = 0; i < klass->interface_count; ++i) {
6183 MonoClass *iface = klass->interfaces [i];
6184 if (!mono_class_get_flags (iface))
6185 return FALSE;
6187 return TRUE;
6190 static gboolean
6191 verify_valuetype_layout_with_target (MonoClass *klass, MonoClass *target_class)
6193 int type;
6194 gpointer iter = NULL;
6195 MonoClassField *field;
6196 MonoClass *field_class;
6198 if (!klass->valuetype)
6199 return TRUE;
6201 type = klass->byval_arg.type;
6202 /*primitive type fields are not properly decoded*/
6203 if ((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_R8) || (type >= MONO_TYPE_I && type <= MONO_TYPE_U))
6204 return TRUE;
6206 while ((field = mono_class_get_fields (klass, &iter)) != NULL) {
6207 if (!field->type)
6208 return FALSE;
6210 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
6211 continue;
6213 field_class = mono_class_get_generic_type_definition (mono_class_from_mono_type (field->type));
6215 if (field_class == target_class || klass == field_class || !verify_valuetype_layout_with_target (field_class, target_class))
6216 return FALSE;
6219 return TRUE;
6222 static gboolean
6223 verify_valuetype_layout (MonoClass *klass)
6225 gboolean res;
6226 res = verify_valuetype_layout_with_target (klass, klass);
6227 return res;
6230 static gboolean
6231 recursive_mark_constraint_args (MonoBitSet *used_args, MonoGenericContainer *gc, MonoType *type)
6233 int idx;
6234 MonoClass **constraints;
6235 MonoGenericParamInfo *param_info;
6237 g_assert (mono_type_is_generic_argument (type));
6239 idx = mono_type_get_generic_param_num (type);
6240 if (mono_bitset_test_fast (used_args, idx))
6241 return FALSE;
6243 mono_bitset_set_fast (used_args, idx);
6244 param_info = mono_generic_container_get_param_info (gc, idx);
6246 if (!param_info->constraints)
6247 return TRUE;
6249 for (constraints = param_info->constraints; *constraints; ++constraints) {
6250 MonoClass *ctr = *constraints;
6251 MonoType *constraint_type = &ctr->byval_arg;
6253 if (mono_type_is_generic_argument (constraint_type) && !recursive_mark_constraint_args (used_args, gc, constraint_type))
6254 return FALSE;
6256 return TRUE;
6259 static gboolean
6260 verify_generic_parameters (MonoClass *klass)
6262 int i;
6263 MonoGenericContainer *gc = mono_class_get_generic_container (klass);
6264 MonoBitSet *used_args = mono_bitset_new (gc->type_argc, 0);
6266 for (i = 0; i < gc->type_argc; ++i) {
6267 MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
6268 MonoClass **constraints;
6270 if (!param_info->constraints)
6271 continue;
6273 mono_bitset_clear_all (used_args);
6274 mono_bitset_set_fast (used_args, i);
6276 for (constraints = param_info->constraints; *constraints; ++constraints) {
6277 MonoClass *ctr = *constraints;
6278 MonoType *constraint_type = &ctr->byval_arg;
6280 if (!mono_class_can_access_class (klass, ctr))
6281 goto fail;
6283 if (!mono_type_is_valid_type_in_context (constraint_type, &gc->context))
6284 goto fail;
6286 if (mono_type_is_generic_argument (constraint_type) && !recursive_mark_constraint_args (used_args, gc, constraint_type))
6287 goto fail;
6288 if (mono_class_is_ginst (ctr) && !mono_class_is_valid_generic_instantiation (NULL, ctr))
6289 goto fail;
6292 mono_bitset_free (used_args);
6293 return TRUE;
6295 fail:
6296 mono_bitset_free (used_args);
6297 return FALSE;
6301 * Check if the class is verifiable.
6303 * Right now there are no conditions that make a class a valid but not verifiable. Both overlapping reference
6304 * field and invalid generic instantiation are fatal errors.
6306 * This method must be safe to be called from mono_class_init and all code must be carefull about that.
6309 gboolean
6310 mono_verifier_verify_class (MonoClass *klass)
6312 /*Neither <Module>, object or ifaces have parent.*/
6313 if (!klass->parent &&
6314 klass != mono_defaults.object_class &&
6315 !MONO_CLASS_IS_INTERFACE (klass) &&
6316 (!image_is_dynamic (klass->image) && klass->type_token != 0x2000001)) /*<Module> is the first type in the assembly*/
6317 return FALSE;
6318 if (klass->parent) {
6319 if (MONO_CLASS_IS_INTERFACE (klass->parent))
6320 return FALSE;
6321 if (!mono_class_is_ginst (klass) && mono_class_is_gtd (klass->parent))
6322 return FALSE;
6323 if (mono_class_is_ginst (klass->parent) && !mono_class_is_ginst (klass)) {
6324 MonoGenericContext *context = mono_class_get_context (klass);
6325 if (mono_class_is_gtd (klass))
6326 context = &mono_class_get_generic_container (klass)->context;
6327 if (!mono_type_is_valid_type_in_context (&klass->parent->byval_arg, context))
6328 return FALSE;
6331 if (mono_class_is_gtd (klass) && (mono_class_is_explicit_layout (klass)))
6332 return FALSE;
6333 if (mono_class_is_gtd (klass) && !verify_generic_parameters (klass))
6334 return FALSE;
6335 if (!verify_class_for_overlapping_reference_fields (klass))
6336 return FALSE;
6337 if (mono_class_is_ginst (klass) && !mono_class_is_valid_generic_instantiation (NULL, klass))
6338 return FALSE;
6339 if (!mono_class_is_ginst (klass) && !verify_class_fields (klass))
6340 return FALSE;
6341 if (klass->valuetype && !verify_valuetype_layout (klass))
6342 return FALSE;
6343 if (!verify_interfaces (klass))
6344 return FALSE;
6345 return TRUE;
6348 gboolean
6349 mono_verifier_class_is_valid_generic_instantiation (MonoClass *klass)
6351 return mono_class_is_valid_generic_instantiation (NULL, klass);
6354 gboolean
6355 mono_verifier_is_method_valid_generic_instantiation (MonoMethod *method)
6357 if (!method->is_inflated)
6358 return TRUE;
6359 return mono_method_is_valid_generic_instantiation (NULL, method);
6362 #else
6364 gboolean
6365 mono_verifier_verify_class (MonoClass *klass)
6367 /* The verifier was disabled at compile time */
6368 return TRUE;
6371 GSList*
6372 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility, gboolean is_fulltrust)
6374 /* The verifier was disabled at compile time */
6375 return NULL;
6378 gboolean
6379 mono_verifier_is_class_full_trust (MonoClass *klass)
6381 /* The verifier was disabled at compile time */
6382 return TRUE;
6385 gboolean
6386 mono_verifier_is_method_full_trust (MonoMethod *method)
6388 /* The verifier was disabled at compile time */
6389 return TRUE;
6392 gboolean
6393 mono_verifier_is_enabled_for_image (MonoImage *image)
6395 /* The verifier was disabled at compile time */
6396 return FALSE;
6399 gboolean
6400 mono_verifier_is_enabled_for_class (MonoClass *klass)
6402 /* The verifier was disabled at compile time */
6403 return FALSE;
6406 gboolean
6407 mono_verifier_is_enabled_for_method (MonoMethod *method)
6409 /* The verifier was disabled at compile time */
6410 return FALSE;
6413 GSList*
6414 mono_method_verify (MonoMethod *method, int level)
6416 /* The verifier was disabled at compile time */
6417 return NULL;
6420 void
6421 mono_free_verify_list (GSList *list)
6423 /* The verifier was disabled at compile time */
6424 /* will always be null if verifier is disabled */
6427 gboolean
6428 mono_verifier_class_is_valid_generic_instantiation (MonoClass *klass)
6430 return TRUE;
6433 gboolean
6434 mono_verifier_is_method_valid_generic_instantiation (MonoMethod *method)
6436 return TRUE;
6441 #endif