Merge pull request #3936 from kumpera/monoclass_reorg2
[mono-project.git] / mono / metadata / verify.c
blob106bae0725557f553a4fbb760eea7b3d04a9ee74
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/metadata/class-internals.h>
32 #include <mono/utils/mono-counters.h>
33 #include <mono/utils/monobitset.h>
34 #include <string.h>
35 #include <ctype.h>
37 static MiniVerifierMode verifier_mode = MONO_VERIFIER_MODE_OFF;
38 static gboolean verify_all = FALSE;
41 * Set the desired level of checks for the verfier.
44 void
45 mono_verifier_set_mode (MiniVerifierMode mode)
47 verifier_mode = mode;
50 void
51 mono_verifier_enable_verify_all ()
53 verify_all = TRUE;
56 #ifndef DISABLE_VERIFIER
58 * Pull the list of opcodes
60 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
61 a = i,
63 enum {
64 #include "mono/cil/opcode.def"
65 LAST = 0xff
67 #undef OPDEF
69 #ifdef MONO_VERIFIER_DEBUG
70 #define VERIFIER_DEBUG(code) do { code } while (0)
71 #else
72 #define VERIFIER_DEBUG(code)
73 #endif
75 //////////////////////////////////////////////////////////////////
76 #define IS_STRICT_MODE(ctx) (((ctx)->level & MONO_VERIFY_NON_STRICT) == 0)
77 #define IS_FAIL_FAST_MODE(ctx) (((ctx)->level & MONO_VERIFY_FAIL_FAST) == MONO_VERIFY_FAIL_FAST)
78 #define IS_SKIP_VISIBILITY(ctx) (((ctx)->level & MONO_VERIFY_SKIP_VISIBILITY) == MONO_VERIFY_SKIP_VISIBILITY)
79 #define IS_REPORT_ALL_ERRORS(ctx) (((ctx)->level & MONO_VERIFY_REPORT_ALL_ERRORS) == MONO_VERIFY_REPORT_ALL_ERRORS)
80 #define CLEAR_PREFIX(ctx, prefix) do { (ctx)->prefix_set &= ~(prefix); } while (0)
81 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
82 do { \
83 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
84 vinfo->info.status = __status; \
85 vinfo->info.message = ( __msg ); \
86 vinfo->exception_type = (__exception); \
87 (__ctx)->list = g_slist_prepend ((__ctx)->list, vinfo); \
88 } while (0)
90 //TODO support MONO_VERIFY_REPORT_ALL_ERRORS
91 #define ADD_VERIFY_ERROR(__ctx, __msg) \
92 do { \
93 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
94 (__ctx)->valid = 0; \
95 } while (0)
97 #define CODE_NOT_VERIFIABLE(__ctx, __msg) \
98 do { \
99 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
100 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, MONO_EXCEPTION_UNVERIFIABLE_IL); \
101 (__ctx)->verifiable = 0; \
102 if (IS_FAIL_FAST_MODE (__ctx)) \
103 (__ctx)->valid = 0; \
105 } while (0)
107 #define ADD_VERIFY_ERROR2(__ctx, __msg, __exception) \
108 do { \
109 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, __exception); \
110 (__ctx)->valid = 0; \
111 } while (0)
113 #define CODE_NOT_VERIFIABLE2(__ctx, __msg, __exception) \
114 do { \
115 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
116 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, __exception); \
117 (__ctx)->verifiable = 0; \
118 if (IS_FAIL_FAST_MODE (__ctx)) \
119 (__ctx)->valid = 0; \
121 } while (0)
123 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
124 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
126 #if SIZEOF_VOID_P == 4
127 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
128 #else
129 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
130 #endif
132 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
133 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
135 /*Flags to be used with ILCodeDesc::flags */
136 enum {
137 /*Instruction has not been processed.*/
138 IL_CODE_FLAG_NOT_PROCESSED = 0,
139 /*Instruction was decoded by mono_method_verify loop.*/
140 IL_CODE_FLAG_SEEN = 1,
141 /*Instruction was target of a branch or is at a protected block boundary.*/
142 IL_CODE_FLAG_WAS_TARGET = 2,
143 /*Used by stack_init to avoid double initialize each entry.*/
144 IL_CODE_FLAG_STACK_INITED = 4,
145 /*Used by merge_stacks to decide if it should just copy the eval stack.*/
146 IL_CODE_STACK_MERGED = 8,
147 /*This instruction is part of the delegate construction sequence, it cannot be target of a branch.*/
148 IL_CODE_DELEGATE_SEQUENCE = 0x10,
149 /*This is a delegate created from a ldftn to a non final virtual method*/
150 IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL = 0x20,
151 /*This is a call to a non final virtual method*/
152 IL_CODE_CALL_NONFINAL_VIRTUAL = 0x40,
155 typedef enum {
156 RESULT_VALID,
157 RESULT_UNVERIFIABLE,
158 RESULT_INVALID
159 } verify_result_t;
161 typedef struct {
162 MonoType *type;
163 int stype;
164 MonoMethod *method;
165 } ILStackDesc;
168 typedef struct {
169 ILStackDesc *stack;
170 guint16 size, max_size;
171 guint16 flags;
172 } ILCodeDesc;
174 typedef struct {
175 int max_args;
176 int max_stack;
177 int verifiable;
178 int valid;
179 int level;
181 int code_size;
182 ILCodeDesc *code;
183 ILCodeDesc eval;
185 MonoType **params;
186 GSList *list;
187 /*Allocated fnptr MonoType that should be freed by us.*/
188 GSList *funptrs;
189 /*Type dup'ed exception types from catch blocks.*/
190 GSList *exception_types;
192 int num_locals;
193 MonoType **locals;
195 /*TODO get rid of target here, need_merge in mono_method_verify and hoist the merging code in the branching code*/
196 int target;
198 guint32 ip_offset;
199 MonoMethodSignature *signature;
200 MonoMethodHeader *header;
202 MonoGenericContext *generic_context;
203 MonoImage *image;
204 MonoMethod *method;
206 /*This flag helps solving a corner case of delegate verification in that you cannot have a "starg 0"
207 *on a method that creates a delegate for a non-final virtual method using ldftn*/
208 gboolean has_this_store;
210 /*This flag is used to control if the contructor of the parent class has been called.
211 *If the this pointer is pushed on the eval stack and it's a reference type constructor and
212 * super_ctor_called is false, the uninitialized flag is set on the pushed value.
214 * Poping an uninitialized this ptr from the eval stack is an unverifiable operation unless
215 * the safe variant is used. Only a few opcodes can use it : dup, pop, ldfld, stfld and call to a constructor.
217 gboolean super_ctor_called;
219 guint32 prefix_set;
220 gboolean has_flags;
221 MonoType *constrained_type;
222 } VerifyContext;
224 static void
225 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external);
227 static int
228 get_stack_type (MonoType *type);
230 static gboolean
231 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn);
233 static gboolean
234 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass);
236 static gboolean
237 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method);
239 static MonoGenericParam*
240 verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type);
242 static gboolean
243 verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate);
244 //////////////////////////////////////////////////////////////////
248 enum {
249 TYPE_INV = 0, /* leave at 0. */
250 TYPE_I4 = 1,
251 TYPE_I8 = 2,
252 TYPE_NATIVE_INT = 3,
253 TYPE_R8 = 4,
254 /* Used by operator tables to resolve pointer types (managed & unmanaged) and by unmanaged pointer types*/
255 TYPE_PTR = 5,
256 /* value types and classes */
257 TYPE_COMPLEX = 6,
258 /* Number of types, used to define the size of the tables*/
259 TYPE_MAX = 6,
261 /* Used by tables to signal that a result is not verifiable*/
262 NON_VERIFIABLE_RESULT = 0x80,
264 /*Mask used to extract just the type, excluding flags */
265 TYPE_MASK = 0x0F,
267 /* The stack type is a managed pointer, unmask the value to res */
268 POINTER_MASK = 0x100,
270 /*Stack type with the pointer mask*/
271 RAW_TYPE_MASK = 0x10F,
273 /* Controlled Mutability Manager Pointer */
274 CMMP_MASK = 0x200,
276 /* The stack type is a null literal*/
277 NULL_LITERAL_MASK = 0x400,
279 /**Used by ldarg.0 and family to let delegate verification happens.*/
280 THIS_POINTER_MASK = 0x800,
282 /**Signals that this is a boxed value type*/
283 BOXED_MASK = 0x1000,
285 /*This is an unitialized this ref*/
286 UNINIT_THIS_MASK = 0x2000,
289 static const char* const
290 type_names [TYPE_MAX + 1] = {
291 "Invalid",
292 "Int32",
293 "Int64",
294 "Native Int",
295 "Float64",
296 "Native Pointer",
297 "Complex"
300 enum {
301 PREFIX_UNALIGNED = 1,
302 PREFIX_VOLATILE = 2,
303 PREFIX_TAIL = 4,
304 PREFIX_CONSTRAINED = 8,
305 PREFIX_READONLY = 16
307 //////////////////////////////////////////////////////////////////
309 #ifdef ENABLE_VERIFIER_STATS
311 #define _MEM_ALLOC(amt) do { allocated_memory += (amt); working_set += (amt); } while (0)
312 #define _MEM_FREE(amt) do { working_set -= (amt); } while (0)
314 static int allocated_memory;
315 static int working_set;
316 static int max_allocated_memory;
317 static int max_working_set;
318 static int total_allocated_memory;
320 static void
321 finish_collect_stats (void)
323 max_allocated_memory = MAX (max_allocated_memory, allocated_memory);
324 max_working_set = MAX (max_working_set, working_set);
325 total_allocated_memory += allocated_memory;
326 allocated_memory = working_set = 0;
329 static void
330 init_verifier_stats (void)
332 static gboolean inited;
333 if (!inited) {
334 inited = TRUE;
335 mono_counters_register ("Maximum memory allocated during verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &max_allocated_memory);
336 mono_counters_register ("Maximum memory used during verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &max_working_set);
337 mono_counters_register ("Total memory allocated for verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &total_allocated_memory);
341 #else
343 #define _MEM_ALLOC(amt) do {} while (0)
344 #define _MEM_FREE(amt) do { } while (0)
346 #define finish_collect_stats()
347 #define init_verifier_stats()
349 #endif
352 //////////////////////////////////////////////////////////////////
355 /*Token validation macros and functions */
356 #define IS_MEMBER_REF(token) (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
357 #define IS_METHOD_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
358 #define IS_METHOD_SPEC(token) (mono_metadata_token_table (token) == MONO_TABLE_METHODSPEC)
359 #define IS_FIELD_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_FIELD)
361 #define IS_TYPE_REF(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPEREF)
362 #define IS_TYPE_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPEDEF)
363 #define IS_TYPE_SPEC(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC)
364 #define IS_METHOD_DEF_OR_REF_OR_SPEC(token) (IS_METHOD_DEF (token) || IS_MEMBER_REF (token) || IS_METHOD_SPEC (token))
365 #define IS_TYPE_DEF_OR_REF_OR_SPEC(token) (IS_TYPE_DEF (token) || IS_TYPE_REF (token) || IS_TYPE_SPEC (token))
366 #define IS_FIELD_DEF_OR_REF(token) (IS_FIELD_DEF (token) || IS_MEMBER_REF (token))
369 * Verify if @token refers to a valid row on int's table.
371 static gboolean
372 token_bounds_check (MonoImage *image, guint32 token)
374 if (image_is_dynamic (image))
375 return mono_dynamic_image_is_valid_token ((MonoDynamicImage*)image, token);
376 return image->tables [mono_metadata_token_table (token)].rows >= mono_metadata_token_index (token) && mono_metadata_token_index (token) > 0;
379 static MonoType *
380 mono_type_create_fnptr_from_mono_method (VerifyContext *ctx, MonoMethod *method)
382 MonoType *res = g_new0 (MonoType, 1);
383 _MEM_ALLOC (sizeof (MonoType));
385 //FIXME use mono_method_get_signature_full
386 res->data.method = mono_method_signature (method);
387 res->type = MONO_TYPE_FNPTR;
388 ctx->funptrs = g_slist_prepend (ctx->funptrs, res);
389 return res;
393 * mono_type_is_enum_type:
395 * Returns: TRUE if @type is an enum type.
397 static gboolean
398 mono_type_is_enum_type (MonoType *type)
400 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)
401 return TRUE;
402 if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype)
403 return TRUE;
404 return FALSE;
408 * mono_type_is_value_type:
410 * Returns: TRUE if @type is named after @namespace.@name.
413 static gboolean
414 mono_type_is_value_type (MonoType *type, const char *namespace_, const char *name)
416 return type->type == MONO_TYPE_VALUETYPE &&
417 !strcmp (namespace_, type->data.klass->name_space) &&
418 !strcmp (name, type->data.klass->name);
422 * Returns TURE if @type is VAR or MVAR
424 static gboolean
425 mono_type_is_generic_argument (MonoType *type)
427 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
431 * mono_type_get_underlying_type_any:
433 * This functions is just like mono_type_get_underlying_type but it doesn't care if the type is byref.
435 * Returns the underlying type of @type regardless if it is byref or not.
437 static MonoType*
438 mono_type_get_underlying_type_any (MonoType *type)
440 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)
441 return mono_class_enum_basetype (type->data.klass);
442 if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype)
443 return mono_class_enum_basetype (type->data.generic_class->container_class);
444 return type;
447 static G_GNUC_UNUSED const char*
448 mono_type_get_stack_name (MonoType *type)
450 return type_names [get_stack_type (type) & TYPE_MASK];
453 #define CTOR_REQUIRED_FLAGS (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_RT_SPECIAL_NAME)
454 #define CTOR_INVALID_FLAGS (METHOD_ATTRIBUTE_STATIC)
456 static gboolean
457 mono_method_is_constructor (MonoMethod *method)
459 return ((method->flags & CTOR_REQUIRED_FLAGS) == CTOR_REQUIRED_FLAGS &&
460 !(method->flags & CTOR_INVALID_FLAGS) &&
461 !strcmp (".ctor", method->name));
464 static gboolean
465 mono_class_has_default_constructor (MonoClass *klass)
467 MonoMethod *method;
468 int i;
470 mono_class_setup_methods (klass);
471 if (mono_class_has_failure (klass))
472 return FALSE;
474 int mcount = mono_class_get_method_count (klass);
475 for (i = 0; i < mcount; ++i) {
476 method = klass->methods [i];
477 if (mono_method_is_constructor (method) &&
478 mono_method_signature (method) &&
479 mono_method_signature (method)->param_count == 0 &&
480 (method->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC)
481 return TRUE;
483 return FALSE;
487 * Verify if @type is valid for the given @ctx verification context.
488 * this function checks for VAR and MVAR types that are invalid under the current verifier,
490 static gboolean
491 mono_type_is_valid_type_in_context_full (MonoType *type, MonoGenericContext *context, gboolean check_gtd)
493 int i;
494 MonoGenericInst *inst;
496 switch (type->type) {
497 case MONO_TYPE_VAR:
498 case MONO_TYPE_MVAR:
499 if (!context)
500 return FALSE;
501 inst = type->type == MONO_TYPE_VAR ? context->class_inst : context->method_inst;
502 if (!inst || mono_type_get_generic_param_num (type) >= inst->type_argc)
503 return FALSE;
504 break;
505 case MONO_TYPE_SZARRAY:
506 return mono_type_is_valid_type_in_context_full (&type->data.klass->byval_arg, context, check_gtd);
507 case MONO_TYPE_ARRAY:
508 return mono_type_is_valid_type_in_context_full (&type->data.array->eklass->byval_arg, context, check_gtd);
509 case MONO_TYPE_PTR:
510 return mono_type_is_valid_type_in_context_full (type->data.type, context, check_gtd);
511 case MONO_TYPE_GENERICINST:
512 inst = type->data.generic_class->context.class_inst;
513 if (!inst->is_open)
514 break;
515 for (i = 0; i < inst->type_argc; ++i)
516 if (!mono_type_is_valid_type_in_context_full (inst->type_argv [i], context, check_gtd))
517 return FALSE;
518 break;
519 case MONO_TYPE_CLASS:
520 case MONO_TYPE_VALUETYPE: {
521 MonoClass *klass = type->data.klass;
523 * It's possible to encode generic'sh types in such a way that they disguise themselves as class or valuetype.
524 * Fixing the type decoding is really tricky since under some cases this behavior is needed, for example, to
525 * have a 'class' type pointing to a 'genericinst' class.
527 * For the runtime these non canonical (weird) encodings work fine, the worst they can cause is some
528 * reflection oddities which are harmless - to security at least.
530 if (klass->byval_arg.type != type->type)
531 return mono_type_is_valid_type_in_context_full (&klass->byval_arg, context, check_gtd);
533 if (check_gtd && mono_class_is_gtd (klass))
534 return FALSE;
535 break;
537 default:
538 break;
540 return TRUE;
543 static gboolean
544 mono_type_is_valid_type_in_context (MonoType *type, MonoGenericContext *context)
546 return mono_type_is_valid_type_in_context_full (type, context, FALSE);
549 /*This function returns NULL if the type is not instantiatable*/
550 static MonoType*
551 verifier_inflate_type (VerifyContext *ctx, MonoType *type, MonoGenericContext *context)
553 MonoError error;
554 MonoType *result;
556 result = mono_class_inflate_generic_type_checked (type, context, &error);
557 if (!mono_error_ok (&error)) {
558 mono_error_cleanup (&error);
559 return NULL;
561 return result;
564 /*A side note here. We don't need to check if arguments are broken since this
565 is only need to be done by the runtime before realizing the type.
567 static gboolean
568 is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
570 MonoError error;
571 int i;
573 if (ginst->type_argc != gc->type_argc)
574 return FALSE;
576 for (i = 0; i < gc->type_argc; ++i) {
577 MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
578 MonoClass *paramClass;
579 MonoClass **constraints;
580 MonoType *param_type = ginst->type_argv [i];
582 /*it's not our job to validate type variables*/
583 if (mono_type_is_generic_argument (param_type))
584 continue;
586 paramClass = mono_class_from_mono_type (param_type);
589 /* A GTD can't be a generic argument.
591 * Due to how types are encoded we must check for the case of a genericinst MonoType and GTD MonoClass.
592 * This happens in cases such as: class Foo<T> { void X() { new Bar<T> (); } }
594 * Open instantiations can have GTDs as this happens when one type is instantiated with others params
595 * and the former has an expansion into the later. For example:
596 * class B<K> {}
597 * class A<T>: B<K> {}
598 * The type A <K> has a parent B<K>, that is inflated into the GTD B<>.
599 * Since A<K> is open, thus not instantiatable, this is valid.
601 if (mono_class_is_gtd (paramClass) && param_type->type != MONO_TYPE_GENERICINST && !ginst->is_open)
602 return FALSE;
604 /*it's not safe to call mono_class_init from here*/
605 if (mono_class_is_ginst (paramClass) && !paramClass->inited) {
606 if (!mono_class_is_valid_generic_instantiation (NULL, paramClass))
607 return FALSE;
610 if (!param_info->constraints && !(param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK))
611 continue;
613 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && (!paramClass->valuetype || mono_class_is_nullable (paramClass)))
614 return FALSE;
616 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && paramClass->valuetype)
617 return FALSE;
619 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !paramClass->valuetype && !mono_class_has_default_constructor (paramClass))
620 return FALSE;
622 if (!param_info->constraints)
623 continue;
625 for (constraints = param_info->constraints; *constraints; ++constraints) {
626 MonoClass *ctr = *constraints;
627 MonoType *inflated;
629 inflated = mono_class_inflate_generic_type_checked (&ctr->byval_arg, context, &error);
630 if (!mono_error_ok (&error)) {
631 mono_error_cleanup (&error);
632 return FALSE;
634 ctr = mono_class_from_mono_type (inflated);
635 mono_metadata_free_type (inflated);
637 /*FIXME maybe we need the same this as verifier_class_is_assignable_from*/
638 if (!mono_class_is_assignable_from_slow (ctr, paramClass))
639 return FALSE;
642 return TRUE;
646 * mono_generic_param_is_constraint_compatible:
648 * Returns: TRUE if @candidate is constraint compatible with @target.
650 * This means that @candidate constraints are a super set of @target constaints
652 static gboolean
653 mono_generic_param_is_constraint_compatible (VerifyContext *ctx, MonoGenericParam *target, MonoGenericParam *candidate, MonoClass *candidate_param_class, MonoGenericContext *context)
655 MonoGenericParamInfo *tinfo = mono_generic_param_info (target);
656 MonoGenericParamInfo *cinfo = mono_generic_param_info (candidate);
657 MonoClass **candidate_class;
658 gboolean class_constraint_satisfied = FALSE;
659 gboolean valuetype_constraint_satisfied = FALSE;
661 int tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
662 int cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
664 if (cinfo->constraints) {
665 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
666 MonoClass *cc;
667 MonoType *inflated = verifier_inflate_type (ctx, &(*candidate_class)->byval_arg, ctx->generic_context);
668 if (!inflated)
669 return FALSE;
670 cc = mono_class_from_mono_type (inflated);
671 mono_metadata_free_type (inflated);
673 if (mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
674 class_constraint_satisfied = TRUE;
675 else if (!mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
676 valuetype_constraint_satisfied = TRUE;
679 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
680 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
682 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
683 return FALSE;
684 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
685 return FALSE;
686 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
687 valuetype_constraint_satisfied)) {
688 return FALSE;
692 if (tinfo->constraints) {
693 MonoClass **target_class;
694 for (target_class = tinfo->constraints; *target_class; ++target_class) {
695 MonoClass *tc;
696 MonoType *inflated = verifier_inflate_type (ctx, &(*target_class)->byval_arg, context);
697 if (!inflated)
698 return FALSE;
699 tc = mono_class_from_mono_type (inflated);
700 mono_metadata_free_type (inflated);
703 * A constraint from @target might inflate into @candidate itself and in that case we don't need
704 * check it's constraints since it satisfy the constraint by itself.
706 if (mono_metadata_type_equal (&tc->byval_arg, &candidate_param_class->byval_arg))
707 continue;
709 if (!cinfo->constraints)
710 return FALSE;
712 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
713 MonoClass *cc;
714 inflated = verifier_inflate_type (ctx, &(*candidate_class)->byval_arg, ctx->generic_context);
715 if (!inflated)
716 return FALSE;
717 cc = mono_class_from_mono_type (inflated);
718 mono_metadata_free_type (inflated);
720 if (verifier_class_is_assignable_from (tc, cc))
721 break;
724 * This happens when we have the following:
726 * Bar<K> where K : IFace
727 * Foo<T, U> where T : U where U : IFace
728 * ...
729 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
732 if (mono_type_is_generic_argument (&cc->byval_arg)) {
733 MonoGenericParam *other_candidate = verifier_get_generic_param_from_type (ctx, &cc->byval_arg);
735 if (mono_generic_param_is_constraint_compatible (ctx, target, other_candidate, cc, context)) {
736 break;
740 if (!*candidate_class)
741 return FALSE;
744 return TRUE;
747 static MonoGenericParam*
748 verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type)
750 MonoGenericContainer *gc;
751 MonoMethod *method = ctx->method;
752 int num;
754 num = mono_type_get_generic_param_num (type);
756 if (type->type == MONO_TYPE_VAR) {
757 MonoClass *gtd = method->klass;
758 if (mono_class_is_ginst (gtd))
759 gtd = mono_class_get_generic_class (gtd)->container_class;
760 gc = mono_class_try_get_generic_container (gtd);
761 } else { //MVAR
762 MonoMethod *gmd = method;
763 if (method->is_inflated)
764 gmd = ((MonoMethodInflated*)method)->declaring;
765 gc = mono_method_get_generic_container (gmd);
767 if (!gc)
768 return NULL;
769 return mono_generic_container_get_param (gc, num);
775 * Verify if @type is valid for the given @ctx verification context.
776 * this function checks for VAR and MVAR types that are invalid under the current verifier,
777 * This means that it either
779 static gboolean
780 is_valid_type_in_context (VerifyContext *ctx, MonoType *type)
782 return mono_type_is_valid_type_in_context (type, ctx->generic_context);
785 static gboolean
786 is_valid_generic_instantiation_in_context (VerifyContext *ctx, MonoGenericInst *ginst, gboolean check_gtd)
788 int i;
789 for (i = 0; i < ginst->type_argc; ++i) {
790 MonoType *type = ginst->type_argv [i];
792 if (!mono_type_is_valid_type_in_context_full (type, ctx->generic_context, TRUE))
793 return FALSE;
795 return TRUE;
798 static gboolean
799 generic_arguments_respect_constraints (VerifyContext *ctx, MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
801 int i;
802 for (i = 0; i < ginst->type_argc; ++i) {
803 MonoType *type = ginst->type_argv [i];
804 MonoGenericParam *target = mono_generic_container_get_param (gc, i);
805 MonoGenericParam *candidate;
806 MonoClass *candidate_class;
808 if (!mono_type_is_generic_argument (type))
809 continue;
811 if (!is_valid_type_in_context (ctx, type))
812 return FALSE;
814 candidate = verifier_get_generic_param_from_type (ctx, type);
815 candidate_class = mono_class_from_mono_type (type);
817 if (!mono_generic_param_is_constraint_compatible (ctx, target, candidate, candidate_class, context))
818 return FALSE;
820 return TRUE;
823 static gboolean
824 mono_method_repect_method_constraints (VerifyContext *ctx, MonoMethod *method)
826 MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
827 MonoGenericInst *ginst = gmethod->context.method_inst;
828 MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
829 return !gc || generic_arguments_respect_constraints (ctx, gc, &gmethod->context, ginst);
832 static gboolean
833 mono_class_repect_method_constraints (VerifyContext *ctx, MonoClass *klass)
835 MonoGenericClass *gklass = mono_class_get_generic_class (klass);
836 MonoGenericInst *ginst = gklass->context.class_inst;
837 MonoGenericContainer *gc = mono_class_get_generic_container (gklass->container_class);
838 return !gc || generic_arguments_respect_constraints (ctx, gc, &gklass->context, ginst);
841 static gboolean
842 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method)
844 MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
845 MonoGenericInst *ginst = gmethod->context.method_inst;
846 MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
847 if (!gc) /*non-generic inflated method - it's part of a generic type */
848 return TRUE;
849 if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst, TRUE))
850 return FALSE;
851 return is_valid_generic_instantiation (gc, &gmethod->context, ginst);
855 static gboolean
856 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass)
858 MonoGenericClass *gklass = mono_class_get_generic_class (klass);
859 MonoGenericInst *ginst = gklass->context.class_inst;
860 MonoGenericContainer *gc = mono_class_get_generic_container (gklass->container_class);
861 if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst, TRUE))
862 return FALSE;
863 return is_valid_generic_instantiation (gc, &gklass->context, ginst);
866 static gboolean
867 mono_type_is_valid_in_context (VerifyContext *ctx, MonoType *type)
869 MonoClass *klass;
871 if (type == NULL) {
872 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid null type at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
873 return FALSE;
876 if (!is_valid_type_in_context (ctx, type)) {
877 char *str = mono_type_full_name (type);
878 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type (%s%s) (argument out of range or %s is not generic) at 0x%04x",
879 str [0] == '!' ? "" : type->type == MONO_TYPE_VAR ? "!" : "!!",
880 str,
881 type->type == MONO_TYPE_VAR ? "class" : "method",
882 ctx->ip_offset),
883 MONO_EXCEPTION_BAD_IMAGE);
884 g_free (str);
885 return FALSE;
888 klass = mono_class_from_mono_type (type);
889 mono_class_init (klass);
890 if (mono_class_has_failure (klass)) {
891 if (mono_class_is_ginst (klass) && !mono_class_is_valid_generic_instantiation (NULL, klass))
892 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);
893 else
894 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);
895 return FALSE;
898 if (mono_class_is_ginst (klass) && mono_class_has_failure (mono_class_get_generic_class (klass)->container_class)) {
899 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);
900 return FALSE;
903 if (!mono_class_is_ginst (klass))
904 return TRUE;
906 if (!mono_class_is_valid_generic_instantiation (ctx, klass)) {
907 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);
908 return FALSE;
911 if (!mono_class_repect_method_constraints (ctx, klass)) {
912 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);
913 return FALSE;
916 return TRUE;
919 static verify_result_t
920 mono_method_is_valid_in_context (VerifyContext *ctx, MonoMethod *method)
922 if (!mono_type_is_valid_in_context (ctx, &method->klass->byval_arg))
923 return RESULT_INVALID;
925 if (!method->is_inflated)
926 return RESULT_VALID;
928 if (!mono_method_is_valid_generic_instantiation (ctx, method)) {
929 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);
930 return RESULT_INVALID;
933 if (!mono_method_repect_method_constraints (ctx, method)) {
934 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));
935 return RESULT_UNVERIFIABLE;
937 return RESULT_VALID;
941 static MonoClassField*
942 verifier_load_field (VerifyContext *ctx, int token, MonoClass **out_klass, const char *opcode) {
943 MonoError error;
944 MonoClassField *field;
945 MonoClass *klass = NULL;
947 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
948 field = (MonoClassField *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
949 klass = field ? field->parent : NULL;
950 } else {
951 if (!IS_FIELD_DEF_OR_REF (token) || !token_bounds_check (ctx->image, token)) {
952 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);
953 return NULL;
956 field = mono_field_from_token_checked (ctx->image, token, &klass, ctx->generic_context, &error);
957 mono_error_cleanup (&error); /*FIXME don't swallow the error */
960 if (!field || !field->parent || !klass) {
961 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);
962 return NULL;
965 if (!mono_type_is_valid_in_context (ctx, &klass->byval_arg))
966 return NULL;
968 if (mono_field_get_flags (field) & FIELD_ATTRIBUTE_LITERAL) {
969 char *type_name = mono_type_get_full_name (field->parent);
970 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot reference literal field %s::%s at 0x%04x", type_name, field->name, ctx->ip_offset));
971 g_free (type_name);
972 return NULL;
975 *out_klass = klass;
976 return field;
979 static MonoMethod*
980 verifier_load_method (VerifyContext *ctx, int token, const char *opcode) {
981 MonoMethod* method;
984 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
985 method = (MonoMethod *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
986 } else {
987 MonoError error;
988 if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
989 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);
990 return NULL;
993 method = mono_get_method_checked (ctx->image, token, NULL, ctx->generic_context, &error);
994 mono_error_cleanup (&error); /* FIXME don't swallow this error */
997 if (!method) {
998 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);
999 return NULL;
1002 if (mono_method_is_valid_in_context (ctx, method) == RESULT_INVALID)
1003 return NULL;
1005 return method;
1008 static MonoType*
1009 verifier_load_type (VerifyContext *ctx, int token, const char *opcode) {
1010 MonoType* type;
1012 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
1013 MonoClass *klass = (MonoClass *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
1014 type = klass ? &klass->byval_arg : NULL;
1015 } else {
1016 MonoError error;
1017 if (!IS_TYPE_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
1018 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid type token 0x%08x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
1019 return NULL;
1021 type = mono_type_get_checked (ctx->image, token, ctx->generic_context, &error);
1022 mono_error_cleanup (&error); /*FIXME don't swallow the error */
1025 if (!type) {
1026 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);
1027 return NULL;
1030 if (!mono_type_is_valid_in_context (ctx, type))
1031 return NULL;
1033 return type;
1037 /* stack_slot_get_type:
1039 * Returns the stack type of @value. This value includes POINTER_MASK.
1041 * Use this function to checks that account for a managed pointer.
1043 static gint32
1044 stack_slot_get_type (ILStackDesc *value)
1046 return value->stype & RAW_TYPE_MASK;
1049 /* stack_slot_get_underlying_type:
1051 * Returns the stack type of @value. This value does not include POINTER_MASK.
1053 * Use this function is cases where the fact that the value could be a managed pointer is
1054 * irrelevant. For example, field load doesn't care about this fact of type on stack.
1056 static gint32
1057 stack_slot_get_underlying_type (ILStackDesc *value)
1059 return value->stype & TYPE_MASK;
1062 /* stack_slot_is_managed_pointer:
1064 * Returns TRUE is @value is a managed pointer.
1066 static gboolean
1067 stack_slot_is_managed_pointer (ILStackDesc *value)
1069 return (value->stype & POINTER_MASK) == POINTER_MASK;
1072 /* stack_slot_is_managed_mutability_pointer:
1074 * Returns TRUE is @value is a managed mutability pointer.
1076 static G_GNUC_UNUSED gboolean
1077 stack_slot_is_managed_mutability_pointer (ILStackDesc *value)
1079 return (value->stype & CMMP_MASK) == CMMP_MASK;
1082 /* stack_slot_is_null_literal:
1084 * Returns TRUE is @value is the null literal.
1086 static gboolean
1087 stack_slot_is_null_literal (ILStackDesc *value)
1089 return (value->stype & NULL_LITERAL_MASK) == NULL_LITERAL_MASK;
1093 /* stack_slot_is_this_pointer:
1095 * Returns TRUE is @value is the this literal
1097 static gboolean
1098 stack_slot_is_this_pointer (ILStackDesc *value)
1100 return (value->stype & THIS_POINTER_MASK) == THIS_POINTER_MASK;
1103 /* stack_slot_is_boxed_value:
1105 * Returns TRUE is @value is a boxed value
1107 static gboolean
1108 stack_slot_is_boxed_value (ILStackDesc *value)
1110 return (value->stype & BOXED_MASK) == BOXED_MASK;
1113 static const char *
1114 stack_slot_get_name (ILStackDesc *value)
1116 return type_names [value->stype & TYPE_MASK];
1119 #define APPEND_WITH_PREDICATE(PRED,NAME) do {\
1120 if (PRED (value)) { \
1121 if (!first) \
1122 g_string_append (str, ", "); \
1123 g_string_append (str, NAME); \
1124 first = FALSE; \
1125 } } while (0)
1127 static char*
1128 stack_slot_stack_type_full_name (ILStackDesc *value)
1130 GString *str = g_string_new ("");
1131 char *result;
1132 gboolean has_pred = FALSE, first = TRUE;
1134 if ((value->stype & TYPE_MASK) != value->stype) {
1135 g_string_append(str, "[");
1136 APPEND_WITH_PREDICATE (stack_slot_is_this_pointer, "this");
1137 APPEND_WITH_PREDICATE (stack_slot_is_boxed_value, "boxed");
1138 APPEND_WITH_PREDICATE (stack_slot_is_null_literal, "null");
1139 APPEND_WITH_PREDICATE (stack_slot_is_managed_mutability_pointer, "cmmp");
1140 APPEND_WITH_PREDICATE (stack_slot_is_managed_pointer, "mp");
1141 has_pred = TRUE;
1144 if (mono_type_is_generic_argument (value->type) && !stack_slot_is_boxed_value (value)) {
1145 if (!has_pred)
1146 g_string_append(str, "[");
1147 if (!first)
1148 g_string_append (str, ", ");
1149 g_string_append (str, "unboxed");
1150 has_pred = TRUE;
1153 if (has_pred)
1154 g_string_append(str, "] ");
1156 g_string_append (str, stack_slot_get_name (value));
1157 result = str->str;
1158 g_string_free (str, FALSE);
1159 return result;
1162 static char*
1163 stack_slot_full_name (ILStackDesc *value)
1165 char *type_name = mono_type_full_name (value->type);
1166 char *stack_name = stack_slot_stack_type_full_name (value);
1167 char *res = g_strdup_printf ("%s (%s)", type_name, stack_name);
1168 g_free (type_name);
1169 g_free (stack_name);
1170 return res;
1173 //////////////////////////////////////////////////////////////////
1174 void
1175 mono_free_verify_list (GSList *list)
1177 MonoVerifyInfoExtended *info;
1178 GSList *tmp;
1180 for (tmp = list; tmp; tmp = tmp->next) {
1181 info = (MonoVerifyInfoExtended *)tmp->data;
1182 g_free (info->info.message);
1183 g_free (info);
1185 g_slist_free (list);
1188 #define ADD_ERROR(list,msg) \
1189 do { \
1190 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1191 vinfo->info.status = MONO_VERIFY_ERROR; \
1192 vinfo->info.message = (msg); \
1193 (list) = g_slist_prepend ((list), vinfo); \
1194 } while (0)
1196 #define ADD_WARN(list,code,msg) \
1197 do { \
1198 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1199 vinfo->info.status = (code); \
1200 vinfo->info.message = (msg); \
1201 (list) = g_slist_prepend ((list), vinfo); \
1202 } while (0)
1204 #define ADD_INVALID(list,msg) \
1205 do { \
1206 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1207 vinfo->status = MONO_VERIFY_ERROR; \
1208 vinfo->message = (msg); \
1209 (list) = g_slist_prepend ((list), vinfo); \
1210 /*G_BREAKPOINT ();*/ \
1211 goto invalid_cil; \
1212 } while (0)
1214 #define CHECK_STACK_UNDERFLOW(num) \
1215 do { \
1216 if (cur_stack < (num)) \
1217 ADD_INVALID (list, g_strdup_printf ("Stack underflow at 0x%04x (%d items instead of %d)", ip_offset, cur_stack, (num))); \
1218 } while (0)
1220 #define CHECK_STACK_OVERFLOW() \
1221 do { \
1222 if (cur_stack >= max_stack) \
1223 ADD_INVALID (list, g_strdup_printf ("Maxstack exceeded at 0x%04x", ip_offset)); \
1224 } while (0)
1227 static int
1228 in_any_block (MonoMethodHeader *header, guint offset)
1230 int i;
1231 MonoExceptionClause *clause;
1233 for (i = 0; i < header->num_clauses; ++i) {
1234 clause = &header->clauses [i];
1235 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1236 return 1;
1237 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1238 return 1;
1239 if (MONO_OFFSET_IN_FILTER (clause, offset))
1240 return 1;
1242 return 0;
1246 * in_any_exception_block:
1248 * Returns TRUE is @offset is part of any exception clause (filter, handler, catch, finally or fault).
1250 static gboolean
1251 in_any_exception_block (MonoMethodHeader *header, guint offset)
1253 int i;
1254 MonoExceptionClause *clause;
1256 for (i = 0; i < header->num_clauses; ++i) {
1257 clause = &header->clauses [i];
1258 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1259 return TRUE;
1260 if (MONO_OFFSET_IN_FILTER (clause, offset))
1261 return TRUE;
1263 return FALSE;
1267 * is_valid_branch_instruction:
1269 * Verify if it's valid to perform a branch from @offset to @target.
1270 * This should be used with br and brtrue/false.
1271 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1272 * The major difference from other similiar functions is that branching into a
1273 * finally/fault block is invalid instead of just unverifiable.
1275 static int
1276 is_valid_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1278 int i;
1279 MonoExceptionClause *clause;
1281 for (i = 0; i < header->num_clauses; ++i) {
1282 clause = &header->clauses [i];
1283 /*branching into a finally block is invalid*/
1284 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) &&
1285 !MONO_OFFSET_IN_HANDLER (clause, offset) &&
1286 MONO_OFFSET_IN_HANDLER (clause, target))
1287 return 2;
1289 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1290 return 1;
1291 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1292 return 1;
1293 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1294 return 1;
1296 return 0;
1300 * is_valid_cmp_branch_instruction:
1302 * Verify if it's valid to perform a branch from @offset to @target.
1303 * This should be used with binary comparison branching instruction, like beq, bge and similars.
1304 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1306 * The major differences from other similar functions are that most errors lead to invalid
1307 * code and only branching out of finally, filter or fault clauses is unverifiable.
1309 static int
1310 is_valid_cmp_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1312 int i;
1313 MonoExceptionClause *clause;
1315 for (i = 0; i < header->num_clauses; ++i) {
1316 clause = &header->clauses [i];
1317 /*branching out of a handler or finally*/
1318 if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE &&
1319 MONO_OFFSET_IN_HANDLER (clause, offset) &&
1320 !MONO_OFFSET_IN_HANDLER (clause, target))
1321 return 1;
1323 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1324 return 2;
1325 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1326 return 2;
1327 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1328 return 2;
1330 return 0;
1334 * A leave can't escape a finally block
1336 static int
1337 is_correct_leave (MonoMethodHeader *header, guint offset, guint target)
1339 int i;
1340 MonoExceptionClause *clause;
1342 for (i = 0; i < header->num_clauses; ++i) {
1343 clause = &header->clauses [i];
1344 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY && MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
1345 return 0;
1346 if (MONO_OFFSET_IN_FILTER (clause, offset))
1347 return 0;
1349 return 1;
1353 * A rethrow can't happen outside of a catch handler.
1355 static int
1356 is_correct_rethrow (MonoMethodHeader *header, guint offset)
1358 int i;
1359 MonoExceptionClause *clause;
1361 for (i = 0; i < header->num_clauses; ++i) {
1362 clause = &header->clauses [i];
1363 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1364 return 1;
1366 return 0;
1370 * An endfinally can't happen outside of a finally/fault handler.
1372 static int
1373 is_correct_endfinally (MonoMethodHeader *header, guint offset)
1375 int i;
1376 MonoExceptionClause *clause;
1378 for (i = 0; i < header->num_clauses; ++i) {
1379 clause = &header->clauses [i];
1380 if (MONO_OFFSET_IN_HANDLER (clause, offset) && (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY))
1381 return 1;
1383 return 0;
1388 * An endfilter can only happens inside a filter clause.
1389 * In non-strict mode filter is allowed inside the handler clause too
1391 static MonoExceptionClause *
1392 is_correct_endfilter (VerifyContext *ctx, guint offset)
1394 int i;
1395 MonoExceptionClause *clause;
1397 for (i = 0; i < ctx->header->num_clauses; ++i) {
1398 clause = &ctx->header->clauses [i];
1399 if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER)
1400 continue;
1401 if (MONO_OFFSET_IN_FILTER (clause, offset))
1402 return clause;
1403 if (!IS_STRICT_MODE (ctx) && MONO_OFFSET_IN_HANDLER (clause, offset))
1404 return clause;
1406 return NULL;
1411 * Non-strict endfilter can happens inside a try block or any handler block
1413 static int
1414 is_unverifiable_endfilter (VerifyContext *ctx, guint offset)
1416 int i;
1417 MonoExceptionClause *clause;
1419 for (i = 0; i < ctx->header->num_clauses; ++i) {
1420 clause = &ctx->header->clauses [i];
1421 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1422 return 1;
1424 return 0;
1427 static gboolean
1428 is_valid_bool_arg (ILStackDesc *arg)
1430 if (stack_slot_is_managed_pointer (arg) || stack_slot_is_boxed_value (arg) || stack_slot_is_null_literal (arg))
1431 return TRUE;
1434 switch (stack_slot_get_underlying_type (arg)) {
1435 case TYPE_I4:
1436 case TYPE_I8:
1437 case TYPE_NATIVE_INT:
1438 case TYPE_PTR:
1439 return TRUE;
1440 case TYPE_COMPLEX:
1441 g_assert (arg->type);
1442 switch (arg->type->type) {
1443 case MONO_TYPE_CLASS:
1444 case MONO_TYPE_STRING:
1445 case MONO_TYPE_OBJECT:
1446 case MONO_TYPE_SZARRAY:
1447 case MONO_TYPE_ARRAY:
1448 case MONO_TYPE_FNPTR:
1449 case MONO_TYPE_PTR:
1450 return TRUE;
1451 case MONO_TYPE_GENERICINST:
1452 /*We need to check if the container class
1453 * of the generic type is a valuetype, iow:
1454 * is it a "class Foo<T>" or a "struct Foo<T>"?
1456 return !arg->type->data.generic_class->container_class->valuetype;
1457 default:
1458 return FALSE;
1460 default:
1461 return FALSE;
1466 /*Type manipulation helper*/
1468 /*Returns the byref version of the supplied MonoType*/
1469 static MonoType*
1470 mono_type_get_type_byref (MonoType *type)
1472 if (type->byref)
1473 return type;
1474 return &mono_class_from_mono_type (type)->this_arg;
1478 /*Returns the byval version of the supplied MonoType*/
1479 static MonoType*
1480 mono_type_get_type_byval (MonoType *type)
1482 if (!type->byref)
1483 return type;
1484 return &mono_class_from_mono_type (type)->byval_arg;
1487 static MonoType*
1488 mono_type_from_stack_slot (ILStackDesc *slot)
1490 if (stack_slot_is_managed_pointer (slot))
1491 return mono_type_get_type_byref (slot->type);
1492 return slot->type;
1495 /*Stack manipulation code*/
1497 static void
1498 ensure_stack_size (ILCodeDesc *stack, int required)
1500 int new_size = 8;
1501 ILStackDesc *tmp;
1503 if (required < stack->max_size)
1504 return;
1506 /* We don't have to worry about the exponential growth since stack_copy prune unused space */
1507 new_size = MAX (8, MAX (required, stack->max_size * 2));
1509 g_assert (new_size >= stack->size);
1510 g_assert (new_size >= required);
1512 tmp = g_new0 (ILStackDesc, new_size);
1513 _MEM_ALLOC (sizeof (ILStackDesc) * new_size);
1515 if (stack->stack) {
1516 if (stack->size)
1517 memcpy (tmp, stack->stack, stack->size * sizeof (ILStackDesc));
1518 g_free (stack->stack);
1519 _MEM_FREE (sizeof (ILStackDesc) * stack->max_size);
1522 stack->stack = tmp;
1523 stack->max_size = new_size;
1526 static void
1527 stack_init (VerifyContext *ctx, ILCodeDesc *state)
1529 if (state->flags & IL_CODE_FLAG_STACK_INITED)
1530 return;
1531 state->size = state->max_size = 0;
1532 state->flags |= IL_CODE_FLAG_STACK_INITED;
1535 static void
1536 stack_copy (ILCodeDesc *to, ILCodeDesc *from)
1538 ensure_stack_size (to, from->size);
1539 to->size = from->size;
1541 /*stack copy happens at merge points, which have small stacks*/
1542 if (from->size)
1543 memcpy (to->stack, from->stack, sizeof (ILStackDesc) * from->size);
1546 static void
1547 copy_stack_value (ILStackDesc *to, ILStackDesc *from)
1549 to->stype = from->stype;
1550 to->type = from->type;
1551 to->method = from->method;
1554 static int
1555 check_underflow (VerifyContext *ctx, int size)
1557 if (ctx->eval.size < size) {
1558 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack underflow, required %d, but have %d at 0x%04x", size, ctx->eval.size, ctx->ip_offset));
1559 return 0;
1561 return 1;
1564 static int
1565 check_overflow (VerifyContext *ctx)
1567 if (ctx->eval.size >= ctx->max_stack) {
1568 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have stack-depth %d at 0x%04x", ctx->eval.size + 1, ctx->ip_offset));
1569 return 0;
1571 return 1;
1574 /*This reject out PTR, FNPTR and TYPEDBYREF*/
1575 static gboolean
1576 check_unmanaged_pointer (VerifyContext *ctx, ILStackDesc *value)
1578 if (stack_slot_get_type (value) == TYPE_PTR) {
1579 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1580 return 0;
1582 return 1;
1585 /*TODO verify if MONO_TYPE_TYPEDBYREF is not allowed here as well.*/
1586 static gboolean
1587 check_unverifiable_type (VerifyContext *ctx, MonoType *type)
1589 if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
1590 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1591 return 0;
1593 return 1;
1596 static ILStackDesc *
1597 stack_push (VerifyContext *ctx)
1599 g_assert (ctx->eval.size < ctx->max_stack);
1600 g_assert (ctx->eval.size <= ctx->eval.max_size);
1602 ensure_stack_size (&ctx->eval, ctx->eval.size + 1);
1604 return & ctx->eval.stack [ctx->eval.size++];
1607 static ILStackDesc *
1608 stack_push_val (VerifyContext *ctx, int stype, MonoType *type)
1610 ILStackDesc *top = stack_push (ctx);
1611 top->stype = stype;
1612 top->type = type;
1613 return top;
1616 static ILStackDesc *
1617 stack_pop (VerifyContext *ctx)
1619 ILStackDesc *ret;
1620 g_assert (ctx->eval.size > 0);
1621 ret = ctx->eval.stack + --ctx->eval.size;
1622 if ((ret->stype & UNINIT_THIS_MASK) == UNINIT_THIS_MASK)
1623 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Found use of uninitialized 'this ptr' ref at 0x%04x", ctx->ip_offset));
1624 return ret;
1627 /* This function allows to safely pop an unititialized this ptr from
1628 * the eval stack without marking the method as unverifiable.
1630 static ILStackDesc *
1631 stack_pop_safe (VerifyContext *ctx)
1633 g_assert (ctx->eval.size > 0);
1634 return ctx->eval.stack + --ctx->eval.size;
1637 /*Positive number distance from stack top. [0] is stack top, [1] is the one below*/
1638 static ILStackDesc*
1639 stack_peek (VerifyContext *ctx, int distance)
1641 g_assert (ctx->eval.size - distance > 0);
1642 return ctx->eval.stack + (ctx->eval.size - 1 - distance);
1645 static ILStackDesc *
1646 stack_push_stack_val (VerifyContext *ctx, ILStackDesc *value)
1648 ILStackDesc *top = stack_push (ctx);
1649 copy_stack_value (top, value);
1650 return top;
1653 /* Returns the MonoType associated with the token, or NULL if it is invalid.
1655 * A boxable type can be either a reference or value type, but cannot be a byref type or an unmanaged pointer
1656 * */
1657 static MonoType*
1658 get_boxable_mono_type (VerifyContext* ctx, int token, const char *opcode)
1660 MonoType *type;
1661 MonoClass *klass;
1663 if (!(type = verifier_load_type (ctx, token, opcode)))
1664 return NULL;
1666 if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
1667 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type for %s at 0x%04x", opcode, ctx->ip_offset));
1668 return NULL;
1671 if (type->type == MONO_TYPE_VOID) {
1672 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type for %s at 0x%04x", opcode, ctx->ip_offset));
1673 return NULL;
1676 if (type->type == MONO_TYPE_TYPEDBYREF)
1677 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid use of typedbyref for %s at 0x%04x", opcode, ctx->ip_offset));
1679 if (!(klass = mono_class_from_mono_type (type)))
1680 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not retrieve type token for %s at 0x%04x", opcode, ctx->ip_offset));
1682 if (mono_class_is_gtd (klass) && type->type != MONO_TYPE_GENERICINST)
1683 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));
1685 check_unverifiable_type (ctx, type);
1686 return type;
1690 /*operation result tables */
1692 static const unsigned char bin_op_table [TYPE_MAX][TYPE_MAX] = {
1693 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1694 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1695 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1696 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1697 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1698 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1701 static const unsigned char add_table [TYPE_MAX][TYPE_MAX] = {
1702 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1703 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1704 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1705 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1706 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1707 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1710 static const unsigned char sub_table [TYPE_MAX][TYPE_MAX] = {
1711 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1712 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1713 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1714 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1715 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1716 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1719 static const unsigned char int_bin_op_table [TYPE_MAX][TYPE_MAX] = {
1720 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1721 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1722 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, 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},
1725 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1728 static const unsigned char shift_op_table [TYPE_MAX][TYPE_MAX] = {
1729 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1730 {TYPE_I8, TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV},
1731 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, 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},
1734 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1737 static const unsigned char cmp_br_op [TYPE_MAX][TYPE_MAX] = {
1738 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1739 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1740 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1741 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1742 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV},
1743 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1746 static const unsigned char cmp_br_eq_op [TYPE_MAX][TYPE_MAX] = {
1747 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1748 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1749 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV},
1750 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1751 {TYPE_INV, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_I4, TYPE_INV},
1752 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4},
1755 static const unsigned char add_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
1756 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1757 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1758 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1759 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1760 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1761 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1764 static const unsigned char sub_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
1765 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1766 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1767 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1768 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1769 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1770 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1773 static const unsigned char bin_ovf_table [TYPE_MAX][TYPE_MAX] = {
1774 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1775 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1776 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, 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},
1779 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1782 #ifdef MONO_VERIFIER_DEBUG
1784 /*debug helpers */
1785 static void
1786 dump_stack_value (ILStackDesc *value)
1788 printf ("[(%x)(%x)", value->type->type, value->stype);
1790 if (stack_slot_is_this_pointer (value))
1791 printf ("[this] ");
1793 if (stack_slot_is_boxed_value (value))
1794 printf ("[boxed] ");
1796 if (stack_slot_is_null_literal (value))
1797 printf ("[null] ");
1799 if (stack_slot_is_managed_mutability_pointer (value))
1800 printf ("Controled Mutability MP: ");
1802 if (stack_slot_is_managed_pointer (value))
1803 printf ("Managed Pointer to: ");
1805 switch (stack_slot_get_underlying_type (value)) {
1806 case TYPE_INV:
1807 printf ("invalid type]");
1808 return;
1809 case TYPE_I4:
1810 printf ("int32]");
1811 return;
1812 case TYPE_I8:
1813 printf ("int64]");
1814 return;
1815 case TYPE_NATIVE_INT:
1816 printf ("native int]");
1817 return;
1818 case TYPE_R8:
1819 printf ("float64]");
1820 return;
1821 case TYPE_PTR:
1822 printf ("unmanaged pointer]");
1823 return;
1824 case TYPE_COMPLEX:
1825 switch (value->type->type) {
1826 case MONO_TYPE_CLASS:
1827 case MONO_TYPE_VALUETYPE:
1828 printf ("complex] (%s)", value->type->data.klass->name);
1829 return;
1830 case MONO_TYPE_STRING:
1831 printf ("complex] (string)");
1832 return;
1833 case MONO_TYPE_OBJECT:
1834 printf ("complex] (object)");
1835 return;
1836 case MONO_TYPE_SZARRAY:
1837 printf ("complex] (%s [])", value->type->data.klass->name);
1838 return;
1839 case MONO_TYPE_ARRAY:
1840 printf ("complex] (%s [%d %d %d])",
1841 value->type->data.array->eklass->name,
1842 value->type->data.array->rank,
1843 value->type->data.array->numsizes,
1844 value->type->data.array->numlobounds);
1845 return;
1846 case MONO_TYPE_GENERICINST:
1847 printf ("complex] (inst of %s )", value->type->data.generic_class->container_class->name);
1848 return;
1849 case MONO_TYPE_VAR:
1850 printf ("complex] (type generic param !%d - %s) ", value->type->data.generic_param->num, mono_generic_param_info (value->type->data.generic_param)->name);
1851 return;
1852 case MONO_TYPE_MVAR:
1853 printf ("complex] (method generic param !!%d - %s) ", value->type->data.generic_param->num, mono_generic_param_info (value->type->data.generic_param)->name);
1854 return;
1855 default: {
1856 //should be a boxed value
1857 char * name = mono_type_full_name (value->type);
1858 printf ("complex] %s", name);
1859 g_free (name);
1860 return;
1863 default:
1864 printf ("unknown stack %x type]\n", value->stype);
1865 g_assert_not_reached ();
1869 static void
1870 dump_stack_state (ILCodeDesc *state)
1872 int i;
1874 printf ("(%d) ", state->size);
1875 for (i = 0; i < state->size; ++i)
1876 dump_stack_value (state->stack + i);
1877 printf ("\n");
1879 #endif
1882 * is_array_type_compatible:
1884 * Returns TRUE if candidate array type can be assigned to target.
1886 * Both parameters MUST be of type MONO_TYPE_ARRAY (target->type == MONO_TYPE_ARRAY)
1888 static gboolean
1889 is_array_type_compatible (MonoType *target, MonoType *candidate)
1891 MonoArrayType *left = target->data.array;
1892 MonoArrayType *right = candidate->data.array;
1894 g_assert (target->type == MONO_TYPE_ARRAY);
1895 g_assert (candidate->type == MONO_TYPE_ARRAY);
1897 if (left->rank != right->rank)
1898 return FALSE;
1900 return verifier_class_is_assignable_from (left->eklass, right->eklass);
1903 static int
1904 get_stack_type (MonoType *type)
1906 int mask = 0;
1907 int type_kind = type->type;
1908 if (type->byref)
1909 mask = POINTER_MASK;
1910 /*TODO handle CMMP_MASK */
1912 handle_enum:
1913 switch (type_kind) {
1914 case MONO_TYPE_I1:
1915 case MONO_TYPE_U1:
1916 case MONO_TYPE_BOOLEAN:
1917 case MONO_TYPE_I2:
1918 case MONO_TYPE_U2:
1919 case MONO_TYPE_CHAR:
1920 case MONO_TYPE_I4:
1921 case MONO_TYPE_U4:
1922 return TYPE_I4 | mask;
1924 case MONO_TYPE_I:
1925 case MONO_TYPE_U:
1926 return TYPE_NATIVE_INT | mask;
1928 /* FIXME: the spec says that you cannot have a pointer to method pointer, do we need to check this here? */
1929 case MONO_TYPE_FNPTR:
1930 case MONO_TYPE_PTR:
1931 case MONO_TYPE_TYPEDBYREF:
1932 return TYPE_PTR | mask;
1934 case MONO_TYPE_VAR:
1935 case MONO_TYPE_MVAR:
1937 case MONO_TYPE_CLASS:
1938 case MONO_TYPE_STRING:
1939 case MONO_TYPE_OBJECT:
1940 case MONO_TYPE_SZARRAY:
1941 case MONO_TYPE_ARRAY:
1942 return TYPE_COMPLEX | mask;
1944 case MONO_TYPE_I8:
1945 case MONO_TYPE_U8:
1946 return TYPE_I8 | mask;
1948 case MONO_TYPE_R4:
1949 case MONO_TYPE_R8:
1950 return TYPE_R8 | mask;
1952 case MONO_TYPE_GENERICINST:
1953 case MONO_TYPE_VALUETYPE:
1954 if (mono_type_is_enum_type (type)) {
1955 type = mono_type_get_underlying_type_any (type);
1956 if (!type)
1957 return FALSE;
1958 type_kind = type->type;
1959 goto handle_enum;
1960 } else {
1961 return TYPE_COMPLEX | mask;
1964 default:
1965 return TYPE_INV;
1969 /* convert MonoType to ILStackDesc format (stype) */
1970 static gboolean
1971 set_stack_value (VerifyContext *ctx, ILStackDesc *stack, MonoType *type, int take_addr)
1973 int mask = 0;
1974 int type_kind = type->type;
1976 if (type->byref || take_addr)
1977 mask = POINTER_MASK;
1978 /* TODO handle CMMP_MASK */
1980 handle_enum:
1981 stack->type = type;
1983 switch (type_kind) {
1984 case MONO_TYPE_I1:
1985 case MONO_TYPE_U1:
1986 case MONO_TYPE_BOOLEAN:
1987 case MONO_TYPE_I2:
1988 case MONO_TYPE_U2:
1989 case MONO_TYPE_CHAR:
1990 case MONO_TYPE_I4:
1991 case MONO_TYPE_U4:
1992 stack->stype = TYPE_I4 | mask;
1993 break;
1994 case MONO_TYPE_I:
1995 case MONO_TYPE_U:
1996 stack->stype = TYPE_NATIVE_INT | mask;
1997 break;
1999 /*FIXME: Do we need to check if it's a pointer to the method pointer? The spec says it' illegal to have that.*/
2000 case MONO_TYPE_FNPTR:
2001 case MONO_TYPE_PTR:
2002 case MONO_TYPE_TYPEDBYREF:
2003 stack->stype = TYPE_PTR | mask;
2004 break;
2006 case MONO_TYPE_CLASS:
2007 case MONO_TYPE_STRING:
2008 case MONO_TYPE_OBJECT:
2009 case MONO_TYPE_SZARRAY:
2010 case MONO_TYPE_ARRAY:
2012 case MONO_TYPE_VAR:
2013 case MONO_TYPE_MVAR:
2014 stack->stype = TYPE_COMPLEX | mask;
2015 break;
2017 case MONO_TYPE_I8:
2018 case MONO_TYPE_U8:
2019 stack->stype = TYPE_I8 | mask;
2020 break;
2021 case MONO_TYPE_R4:
2022 case MONO_TYPE_R8:
2023 stack->stype = TYPE_R8 | mask;
2024 break;
2025 case MONO_TYPE_GENERICINST:
2026 case MONO_TYPE_VALUETYPE:
2027 if (mono_type_is_enum_type (type)) {
2028 MonoType *utype = mono_type_get_underlying_type_any (type);
2029 if (!utype) {
2030 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not resolve underlying type of %x at %d", type->type, ctx->ip_offset));
2031 return FALSE;
2033 type = utype;
2034 type_kind = type->type;
2035 goto handle_enum;
2036 } else {
2037 stack->stype = TYPE_COMPLEX | mask;
2038 break;
2040 default:
2041 VERIFIER_DEBUG ( printf ("unknown type 0x%02x in eval stack type\n", type->type); );
2042 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Illegal value set on stack 0x%02x at %d", type->type, ctx->ip_offset));
2043 return FALSE;
2045 return TRUE;
2049 * init_stack_with_value_at_exception_boundary:
2051 * Initialize the stack and push a given type.
2052 * The instruction is marked as been on the exception boundary.
2054 static void
2055 init_stack_with_value_at_exception_boundary (VerifyContext *ctx, ILCodeDesc *code, MonoClass *klass)
2057 MonoError error;
2058 MonoType *type = mono_class_inflate_generic_type_checked (&klass->byval_arg, ctx->generic_context, &error);
2060 if (!mono_error_ok (&error)) {
2061 char *name = mono_type_get_full_name (klass);
2062 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid class %s used for exception", name));
2063 g_free (name);
2064 mono_error_cleanup (&error);
2065 return;
2068 if (!ctx->max_stack) {
2069 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack overflow at 0x%04x", ctx->ip_offset));
2070 return;
2073 stack_init (ctx, code);
2074 ensure_stack_size (code, 1);
2075 set_stack_value (ctx, code->stack, type, FALSE);
2076 ctx->exception_types = g_slist_prepend (ctx->exception_types, type);
2077 code->size = 1;
2078 code->flags |= IL_CODE_FLAG_WAS_TARGET;
2079 if (mono_type_is_generic_argument (type))
2080 code->stack->stype |= BOXED_MASK;
2082 /* Class lazy loading functions */
2083 static GENERATE_GET_CLASS_WITH_CACHE (ienumerable, System.Collections.Generic, IEnumerable`1)
2084 static GENERATE_GET_CLASS_WITH_CACHE (icollection, System.Collections.Generic, ICollection`1)
2085 static GENERATE_GET_CLASS_WITH_CACHE (ireadonly_list, System.Collections.Generic, IReadOnlyList`1)
2086 static GENERATE_GET_CLASS_WITH_CACHE (ireadonly_collection, System.Collections.Generic, IReadOnlyCollection`1)
2089 static MonoClass*
2090 get_ienumerable_class (void)
2092 return mono_class_get_ienumerable_class ();
2095 static MonoClass*
2096 get_icollection_class (void)
2098 return mono_class_get_icollection_class ();
2101 static MonoClass*
2102 get_ireadonlylist_class (void)
2104 return mono_class_get_ireadonly_list_class ();
2107 static MonoClass*
2108 get_ireadonlycollection_class (void)
2110 return mono_class_get_ireadonly_collection_class ();
2113 static MonoClass*
2114 inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
2116 MonoType *args [1];
2117 args [0] = &arg0->byval_arg;
2119 return mono_class_bind_generic_parameters (gtype, 1, args, FALSE);
2122 static gboolean
2123 verifier_inflate_and_check_compat (MonoClass *target, MonoClass *gtd, MonoClass *arg)
2125 MonoClass *tmp;
2126 if (!(tmp = inflate_class_one_arg (gtd, arg)))
2127 return FALSE;
2128 if (mono_class_is_variant_compatible (target, tmp, TRUE))
2129 return TRUE;
2130 return FALSE;
2133 static gboolean
2134 verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate)
2136 MonoClass *iface_gtd;
2138 if (target == candidate)
2139 return TRUE;
2141 if (mono_class_has_variant_generic_params (target)) {
2142 if (MONO_CLASS_IS_INTERFACE (target)) {
2143 if (MONO_CLASS_IS_INTERFACE (candidate) && mono_class_is_variant_compatible (target, candidate, TRUE))
2144 return TRUE;
2146 if (candidate->rank == 1) {
2147 if (verifier_inflate_and_check_compat (target, mono_defaults.generic_ilist_class, candidate->element_class))
2148 return TRUE;
2149 if (verifier_inflate_and_check_compat (target, get_icollection_class (), candidate->element_class))
2150 return TRUE;
2151 if (verifier_inflate_and_check_compat (target, get_ienumerable_class (), candidate->element_class))
2152 return TRUE;
2153 if (verifier_inflate_and_check_compat (target, get_ireadonlylist_class (), candidate->element_class))
2154 return TRUE;
2155 if (verifier_inflate_and_check_compat (target, get_ireadonlycollection_class (), candidate->element_class))
2156 return TRUE;
2157 } else {
2158 MonoError error;
2159 int i;
2160 while (candidate && candidate != mono_defaults.object_class) {
2161 mono_class_setup_interfaces (candidate, &error);
2162 if (!mono_error_ok (&error)) {
2163 mono_error_cleanup (&error);
2164 return FALSE;
2167 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
2168 for (i = 0; i < candidate->interface_offsets_count; ++i) {
2169 MonoClass *iface = candidate->interfaces_packed [i];
2170 if (mono_class_is_variant_compatible (target, iface, TRUE))
2171 return TRUE;
2174 for (i = 0; i < candidate->interface_count; ++i) {
2175 MonoClass *iface = candidate->interfaces [i];
2176 if (mono_class_is_variant_compatible (target, iface, TRUE))
2177 return TRUE;
2179 candidate = candidate->parent;
2182 } else if (target->delegate) {
2183 if (mono_class_is_variant_compatible (target, candidate, TRUE))
2184 return TRUE;
2186 return FALSE;
2189 if (mono_class_is_assignable_from (target, candidate))
2190 return TRUE;
2192 if (!MONO_CLASS_IS_INTERFACE (target) || !mono_class_is_ginst (target) || candidate->rank != 1)
2193 return FALSE;
2195 iface_gtd = mono_class_get_generic_class (target)->container_class;
2196 if (iface_gtd != mono_defaults.generic_ilist_class && iface_gtd != get_icollection_class () && iface_gtd != get_ienumerable_class ())
2197 return FALSE;
2199 target = mono_class_from_mono_type (mono_class_get_generic_class (target)->context.class_inst->type_argv [0]);
2200 candidate = candidate->element_class;
2202 return TRUE;
2205 /*Verify if type 'candidate' can be stored in type 'target'.
2207 * If strict, check for the underlying type and not the verification stack types
2209 static gboolean
2210 verify_type_compatibility_full (VerifyContext *ctx, MonoType *target, MonoType *candidate, gboolean strict)
2212 #define IS_ONE_OF3(T, A, B, C) (T == A || T == B || T == C)
2213 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
2215 MonoType *original_candidate = candidate;
2216 VERIFIER_DEBUG ( printf ("checking type compatibility %s x %s strict %d\n", mono_type_full_name (target), mono_type_full_name (candidate), strict); );
2218 /*only one is byref */
2219 if (candidate->byref ^ target->byref) {
2220 /* converting from native int to byref*/
2221 if (get_stack_type (candidate) == TYPE_NATIVE_INT && target->byref) {
2222 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("using byref native int at 0x%04x", ctx->ip_offset));
2223 return TRUE;
2225 return FALSE;
2227 strict |= target->byref;
2228 /*From now on we don't care about byref anymore, so it's ok to discard it here*/
2229 candidate = mono_type_get_underlying_type_any (candidate);
2231 handle_enum:
2232 switch (target->type) {
2233 case MONO_TYPE_VOID:
2234 return candidate->type == MONO_TYPE_VOID;
2235 case MONO_TYPE_I1:
2236 case MONO_TYPE_U1:
2237 case MONO_TYPE_BOOLEAN:
2238 if (strict)
2239 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I1, MONO_TYPE_U1, MONO_TYPE_BOOLEAN);
2240 case MONO_TYPE_I2:
2241 case MONO_TYPE_U2:
2242 case MONO_TYPE_CHAR:
2243 if (strict)
2244 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I2, MONO_TYPE_U2, MONO_TYPE_CHAR);
2245 case MONO_TYPE_I4:
2246 case MONO_TYPE_U4: {
2247 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2248 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2249 if (strict)
2250 return is_native_int || is_int4;
2251 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2254 case MONO_TYPE_I8:
2255 case MONO_TYPE_U8:
2256 return IS_ONE_OF2 (candidate->type, MONO_TYPE_I8, MONO_TYPE_U8);
2258 case MONO_TYPE_R4:
2259 case MONO_TYPE_R8:
2260 if (strict)
2261 return candidate->type == target->type;
2262 return IS_ONE_OF2 (candidate->type, MONO_TYPE_R4, MONO_TYPE_R8);
2264 case MONO_TYPE_I:
2265 case MONO_TYPE_U: {
2266 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2267 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2268 if (strict)
2269 return is_native_int || is_int4;
2270 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2273 case MONO_TYPE_PTR:
2274 if (candidate->type != MONO_TYPE_PTR)
2275 return FALSE;
2276 /* check the underlying type */
2277 return verify_type_compatibility_full (ctx, target->data.type, candidate->data.type, TRUE);
2279 case MONO_TYPE_FNPTR: {
2280 MonoMethodSignature *left, *right;
2281 if (candidate->type != MONO_TYPE_FNPTR)
2282 return FALSE;
2284 left = mono_type_get_signature (target);
2285 right = mono_type_get_signature (candidate);
2286 return mono_metadata_signature_equal (left, right) && left->call_convention == right->call_convention;
2289 case MONO_TYPE_GENERICINST: {
2290 MonoClass *target_klass;
2291 MonoClass *candidate_klass;
2292 if (mono_type_is_enum_type (target)) {
2293 target = mono_type_get_underlying_type_any (target);
2294 if (!target)
2295 return FALSE;
2296 goto handle_enum;
2299 * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
2300 * to take boxing status into account.
2302 if (mono_type_is_generic_argument (original_candidate))
2303 return FALSE;
2305 target_klass = mono_class_from_mono_type (target);
2306 candidate_klass = mono_class_from_mono_type (candidate);
2307 if (mono_class_is_nullable (target_klass)) {
2308 if (!mono_class_is_nullable (candidate_klass))
2309 return FALSE;
2310 return target_klass == candidate_klass;
2312 return verifier_class_is_assignable_from (target_klass, candidate_klass);
2315 case MONO_TYPE_STRING:
2316 return candidate->type == MONO_TYPE_STRING;
2318 case MONO_TYPE_CLASS:
2320 * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
2321 * to take boxing status into account.
2323 if (mono_type_is_generic_argument (original_candidate))
2324 return FALSE;
2326 if (candidate->type == MONO_TYPE_VALUETYPE)
2327 return FALSE;
2329 /* If candidate is an enum it should return true for System.Enum and supertypes.
2330 * That's why here we use the original type and not the underlying type.
2332 return verifier_class_is_assignable_from (target->data.klass, mono_class_from_mono_type (original_candidate));
2334 case MONO_TYPE_OBJECT:
2335 return MONO_TYPE_IS_REFERENCE (candidate);
2337 case MONO_TYPE_SZARRAY: {
2338 MonoClass *left;
2339 MonoClass *right;
2340 if (candidate->type != MONO_TYPE_SZARRAY)
2341 return FALSE;
2343 left = mono_class_from_mono_type (target);
2344 right = mono_class_from_mono_type (candidate);
2346 return verifier_class_is_assignable_from (left, right);
2349 case MONO_TYPE_ARRAY:
2350 if (candidate->type != MONO_TYPE_ARRAY)
2351 return FALSE;
2352 return is_array_type_compatible (target, candidate);
2354 case MONO_TYPE_TYPEDBYREF:
2355 return candidate->type == MONO_TYPE_TYPEDBYREF;
2357 case MONO_TYPE_VALUETYPE: {
2358 MonoClass *target_klass;
2359 MonoClass *candidate_klass;
2361 if (candidate->type == MONO_TYPE_CLASS)
2362 return FALSE;
2364 target_klass = mono_class_from_mono_type (target);
2365 candidate_klass = mono_class_from_mono_type (candidate);
2366 if (target_klass == candidate_klass)
2367 return TRUE;
2368 if (mono_type_is_enum_type (target)) {
2369 target = mono_type_get_underlying_type_any (target);
2370 if (!target)
2371 return FALSE;
2372 goto handle_enum;
2374 return FALSE;
2377 case MONO_TYPE_VAR:
2378 if (candidate->type != MONO_TYPE_VAR)
2379 return FALSE;
2380 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2382 case MONO_TYPE_MVAR:
2383 if (candidate->type != MONO_TYPE_MVAR)
2384 return FALSE;
2385 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2387 default:
2388 VERIFIER_DEBUG ( printf ("unknown store type %d\n", target->type); );
2389 g_assert_not_reached ();
2390 return FALSE;
2392 return 1;
2393 #undef IS_ONE_OF3
2394 #undef IS_ONE_OF2
2397 static gboolean
2398 verify_type_compatibility (VerifyContext *ctx, MonoType *target, MonoType *candidate)
2400 return verify_type_compatibility_full (ctx, target, candidate, FALSE);
2404 * Returns the generic param bound to the context been verified.
2407 static MonoGenericParam*
2408 get_generic_param (VerifyContext *ctx, MonoType *param)
2410 guint16 param_num = mono_type_get_generic_param_num (param);
2411 if (param->type == MONO_TYPE_VAR) {
2412 if (!ctx->generic_context->class_inst || ctx->generic_context->class_inst->type_argc <= param_num) {
2413 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic type argument %d", param_num));
2414 return NULL;
2416 return ctx->generic_context->class_inst->type_argv [param_num]->data.generic_param;
2419 /*param must be a MVAR */
2420 if (!ctx->generic_context->method_inst || ctx->generic_context->method_inst->type_argc <= param_num) {
2421 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic method argument %d", param_num));
2422 return NULL;
2424 return ctx->generic_context->method_inst->type_argv [param_num]->data.generic_param;
2428 static gboolean
2429 recursive_boxed_constraint_type_check (VerifyContext *ctx, MonoType *type, MonoClass *constraint_class, int recursion_level)
2431 MonoType *constraint_type = &constraint_class->byval_arg;
2432 if (recursion_level <= 0)
2433 return FALSE;
2435 if (verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (constraint_type), FALSE))
2436 return TRUE;
2438 if (mono_type_is_generic_argument (constraint_type)) {
2439 MonoGenericParam *param = get_generic_param (ctx, constraint_type);
2440 MonoClass **klass;
2441 if (!param)
2442 return FALSE;
2443 for (klass = mono_generic_param_info (param)->constraints; klass && *klass; ++klass) {
2444 if (recursive_boxed_constraint_type_check (ctx, type, *klass, recursion_level - 1))
2445 return TRUE;
2448 return FALSE;
2451 /**
2452 * is_compatible_boxed_valuetype:
2454 * Returns: TRUE if @candidate / @stack is a valid boxed valuetype.
2456 * @type The source type. It it tested to be of the proper type.
2457 * @candidate type of the boxed valuetype.
2458 * @stack stack slot of the boxed valuetype, separate from @candidade since one could be changed before calling this function
2459 * @strict if TRUE candidate must be boxed compatible to the target type
2462 static gboolean
2463 is_compatible_boxed_valuetype (VerifyContext *ctx, MonoType *type, MonoType *candidate, ILStackDesc *stack, gboolean strict)
2465 if (!stack_slot_is_boxed_value (stack))
2466 return FALSE;
2467 if (type->byref || candidate->byref)
2468 return FALSE;
2470 if (mono_type_is_generic_argument (candidate)) {
2471 MonoGenericParam *param = get_generic_param (ctx, candidate);
2472 MonoClass **klass;
2473 if (!param)
2474 return FALSE;
2476 for (klass = mono_generic_param_info (param)->constraints; klass && *klass; ++klass) {
2477 /*256 should be enough since there can't be more than 255 generic arguments.*/
2478 if (recursive_boxed_constraint_type_check (ctx, type, *klass, 256))
2479 return TRUE;
2483 if (mono_type_is_generic_argument (type))
2484 return FALSE;
2486 if (!strict)
2487 return TRUE;
2489 return MONO_TYPE_IS_REFERENCE (type) && verifier_class_is_assignable_from (mono_class_from_mono_type (type), mono_class_from_mono_type (candidate));
2492 static int
2493 verify_stack_type_compatibility_full (VerifyContext *ctx, MonoType *type, ILStackDesc *stack, gboolean drop_byref, gboolean valuetype_must_be_boxed)
2495 MonoType *candidate = mono_type_from_stack_slot (stack);
2496 if (MONO_TYPE_IS_REFERENCE (type) && !type->byref && stack_slot_is_null_literal (stack))
2497 return TRUE;
2499 if (is_compatible_boxed_valuetype (ctx, type, candidate, stack, TRUE))
2500 return TRUE;
2502 if (valuetype_must_be_boxed && !stack_slot_is_boxed_value (stack) && !MONO_TYPE_IS_REFERENCE (candidate))
2503 return FALSE;
2505 if (!valuetype_must_be_boxed && stack_slot_is_boxed_value (stack))
2506 return FALSE;
2508 if (drop_byref)
2509 return verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (candidate), FALSE);
2511 /* Handle how Roslyn emit fixed statements by encoding it as byref */
2512 if (type->byref && candidate->byref && (type->type == MONO_TYPE_I) && !mono_type_is_reference (candidate)) {
2513 if (!IS_STRICT_MODE (ctx))
2514 return TRUE;
2517 return verify_type_compatibility_full (ctx, type, candidate, FALSE);
2520 static int
2521 verify_stack_type_compatibility (VerifyContext *ctx, MonoType *type, ILStackDesc *stack)
2523 return verify_stack_type_compatibility_full (ctx, type, stack, FALSE, FALSE);
2526 static gboolean
2527 mono_delegate_type_equal (MonoType *target, MonoType *candidate)
2529 if (candidate->byref ^ target->byref)
2530 return FALSE;
2532 switch (target->type) {
2533 case MONO_TYPE_VOID:
2534 case MONO_TYPE_I1:
2535 case MONO_TYPE_U1:
2536 case MONO_TYPE_BOOLEAN:
2537 case MONO_TYPE_I2:
2538 case MONO_TYPE_U2:
2539 case MONO_TYPE_CHAR:
2540 case MONO_TYPE_I4:
2541 case MONO_TYPE_U4:
2542 case MONO_TYPE_I8:
2543 case MONO_TYPE_U8:
2544 case MONO_TYPE_R4:
2545 case MONO_TYPE_R8:
2546 case MONO_TYPE_I:
2547 case MONO_TYPE_U:
2548 case MONO_TYPE_STRING:
2549 case MONO_TYPE_TYPEDBYREF:
2550 return candidate->type == target->type;
2552 case MONO_TYPE_PTR:
2553 if (candidate->type != MONO_TYPE_PTR)
2554 return FALSE;
2555 return mono_delegate_type_equal (target->data.type, candidate->data.type);
2557 case MONO_TYPE_FNPTR:
2558 if (candidate->type != MONO_TYPE_FNPTR)
2559 return FALSE;
2560 return mono_delegate_signature_equal (mono_type_get_signature (target), mono_type_get_signature (candidate), FALSE);
2562 case MONO_TYPE_GENERICINST: {
2563 MonoClass *target_klass;
2564 MonoClass *candidate_klass;
2565 target_klass = mono_class_from_mono_type (target);
2566 candidate_klass = mono_class_from_mono_type (candidate);
2567 /*FIXME handle nullables and enum*/
2568 return verifier_class_is_assignable_from (target_klass, candidate_klass);
2570 case MONO_TYPE_OBJECT:
2571 return MONO_TYPE_IS_REFERENCE (candidate);
2573 case MONO_TYPE_CLASS:
2574 return verifier_class_is_assignable_from(target->data.klass, mono_class_from_mono_type (candidate));
2576 case MONO_TYPE_SZARRAY:
2577 if (candidate->type != MONO_TYPE_SZARRAY)
2578 return FALSE;
2579 return verifier_class_is_assignable_from (mono_class_from_mono_type (target)->element_class, mono_class_from_mono_type (candidate)->element_class);
2581 case MONO_TYPE_ARRAY:
2582 if (candidate->type != MONO_TYPE_ARRAY)
2583 return FALSE;
2584 return is_array_type_compatible (target, candidate);
2586 case MONO_TYPE_VALUETYPE:
2587 /*FIXME handle nullables and enum*/
2588 return mono_class_from_mono_type (candidate) == mono_class_from_mono_type (target);
2590 case MONO_TYPE_VAR:
2591 return candidate->type == MONO_TYPE_VAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2592 return FALSE;
2594 case MONO_TYPE_MVAR:
2595 return candidate->type == MONO_TYPE_MVAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2596 return FALSE;
2598 default:
2599 VERIFIER_DEBUG ( printf ("Unknown type %d. Implement me!\n", target->type); );
2600 g_assert_not_reached ();
2601 return FALSE;
2605 static gboolean
2606 mono_delegate_param_equal (MonoType *delegate, MonoType *method)
2608 if (mono_metadata_type_equal_full (delegate, method, TRUE))
2609 return TRUE;
2611 return mono_delegate_type_equal (method, delegate);
2614 static gboolean
2615 mono_delegate_ret_equal (MonoType *delegate, MonoType *method)
2617 if (mono_metadata_type_equal_full (delegate, method, TRUE))
2618 return TRUE;
2620 return mono_delegate_type_equal (delegate, method);
2624 * mono_delegate_signature_equal:
2626 * Compare two signatures in the way expected by delegates.
2628 * This function only exists due to the fact that it should ignore the 'has_this' part of the signature.
2630 * FIXME can this function be eliminated and proper metadata functionality be used?
2632 static gboolean
2633 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn)
2635 int i;
2636 int method_offset = is_static_ldftn ? 1 : 0;
2638 if (delegate_sig->param_count + method_offset != method_sig->param_count)
2639 return FALSE;
2641 if (delegate_sig->call_convention != method_sig->call_convention)
2642 return FALSE;
2644 for (i = 0; i < delegate_sig->param_count; i++) {
2645 MonoType *p1 = delegate_sig->params [i];
2646 MonoType *p2 = method_sig->params [i + method_offset];
2648 if (!mono_delegate_param_equal (p1, p2))
2649 return FALSE;
2652 if (!mono_delegate_ret_equal (delegate_sig->ret, method_sig->ret))
2653 return FALSE;
2655 return TRUE;
2658 gboolean
2659 mono_verifier_is_signature_compatible (MonoMethodSignature *target, MonoMethodSignature *candidate)
2661 return mono_delegate_signature_equal (target, candidate, FALSE);
2665 * verify_ldftn_delegate:
2667 * Verify properties of ldftn based delegates.
2669 static void
2670 verify_ldftn_delegate (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2672 MonoMethod *method = funptr->method;
2674 /*ldftn non-final virtuals only allowed if method is not static,
2675 * the object is a this arg (comes from a ldarg.0), and there is no starg.0.
2676 * This rules doesn't apply if the object on stack is a boxed valuetype.
2678 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !mono_class_is_sealed (method->klass) && !stack_slot_is_boxed_value (value)) {
2679 /*A stdarg 0 must not happen, we fail here only in fail fast mode to avoid double error reports*/
2680 if (IS_FAIL_FAST_MODE (ctx) && ctx->has_this_store)
2681 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at 0x%04x", ctx->ip_offset));
2683 /*current method must not be static*/
2684 if (ctx->method->flags & METHOD_ATTRIBUTE_STATIC)
2685 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function at 0x%04x", ctx->ip_offset));
2687 /*value is the this pointer, loaded using ldarg.0 */
2688 if (!stack_slot_is_this_pointer (value))
2689 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));
2691 ctx->code [ctx->ip_offset].flags |= IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL;
2696 * verify_delegate_compatibility:
2698 * Verify delegate creation sequence.
2701 static void
2702 verify_delegate_compatibility (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2704 #define IS_VALID_OPCODE(offset, opcode) (ip [ip_offset - offset] == opcode && (ctx->code [ip_offset - offset].flags & IL_CODE_FLAG_SEEN))
2705 #define IS_LOAD_FUN_PTR(kind) (IS_VALID_OPCODE (6, CEE_PREFIX1) && ip [ip_offset - 5] == kind)
2707 MonoMethod *invoke, *method;
2708 const guint8 *ip = ctx->header->code;
2709 guint32 ip_offset = ctx->ip_offset;
2710 gboolean is_static_ldftn = FALSE, is_first_arg_bound = FALSE;
2712 if (stack_slot_get_type (funptr) != TYPE_PTR || !funptr->method) {
2713 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid function pointer parameter for delegate constructor at 0x%04x", ctx->ip_offset));
2714 return;
2717 invoke = mono_get_delegate_invoke (delegate);
2718 method = funptr->method;
2720 if (!method || !mono_method_signature (method)) {
2721 char *name = mono_type_get_full_name (delegate);
2722 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid method on stack to create delegate %s construction at 0x%04x", name, ctx->ip_offset));
2723 g_free (name);
2724 return;
2727 if (!invoke || !mono_method_signature (invoke)) {
2728 char *name = mono_type_get_full_name (delegate);
2729 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Delegate type %s with bad Invoke method at 0x%04x", name, ctx->ip_offset));
2730 g_free (name);
2731 return;
2734 is_static_ldftn = (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) && method->flags & METHOD_ATTRIBUTE_STATIC;
2736 if (is_static_ldftn)
2737 is_first_arg_bound = mono_method_signature (invoke)->param_count + 1 == mono_method_signature (method)->param_count;
2739 if (!mono_delegate_signature_equal (mono_method_signature (invoke), mono_method_signature (method), is_first_arg_bound)) {
2740 char *fun_sig = mono_signature_get_desc (mono_method_signature (method), FALSE);
2741 char *invoke_sig = mono_signature_get_desc (mono_method_signature (invoke), FALSE);
2742 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));
2743 g_free (fun_sig);
2744 g_free (invoke_sig);
2748 * Delegate code sequences:
2749 * [-6] ldftn token
2750 * newobj ...
2753 * [-7] dup
2754 * [-6] ldvirtftn token
2755 * newobj ...
2757 * ldftn sequence:*/
2758 if (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) {
2759 verify_ldftn_delegate (ctx, delegate, value, funptr);
2760 } else if (ip_offset > 6 && IS_VALID_OPCODE (7, CEE_DUP) && IS_LOAD_FUN_PTR (CEE_LDVIRTFTN)) {
2761 ctx->code [ip_offset - 6].flags |= IL_CODE_DELEGATE_SEQUENCE;
2762 }else {
2763 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid code sequence for delegate creation at 0x%04x", ctx->ip_offset));
2765 ctx->code [ip_offset].flags |= IL_CODE_DELEGATE_SEQUENCE;
2767 //general tests
2768 if (is_first_arg_bound) {
2769 if (mono_method_signature (method)->param_count == 0 || !verify_stack_type_compatibility_full (ctx, mono_method_signature (method)->params [0], value, FALSE, TRUE))
2770 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2771 } else {
2772 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
2773 if (!stack_slot_is_null_literal (value))
2774 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Non-null this args used with static function for delegate creation at 0x%04x", ctx->ip_offset));
2775 } else {
2776 if (!verify_stack_type_compatibility_full (ctx, &method->klass->byval_arg, value, FALSE, TRUE) && !stack_slot_is_null_literal (value))
2777 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2781 if (stack_slot_get_type (value) != TYPE_COMPLEX)
2782 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid first parameter for delegate creation at 0x%04x", ctx->ip_offset));
2784 #undef IS_VALID_OPCODE
2785 #undef IS_LOAD_FUN_PTR
2788 /* implement the opcode checks*/
2789 static void
2790 push_arg (VerifyContext *ctx, unsigned int arg, int take_addr)
2792 ILStackDesc *top;
2794 if (arg >= ctx->max_args) {
2795 if (take_addr)
2796 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2797 else {
2798 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2799 if (check_overflow (ctx)) //FIXME: what sane value could we ever push?
2800 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
2802 } else if (check_overflow (ctx)) {
2803 /*We must let the value be pushed, otherwise we would get an underflow error*/
2804 check_unverifiable_type (ctx, ctx->params [arg]);
2805 if (ctx->params [arg]->byref && take_addr)
2806 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2807 top = stack_push (ctx);
2808 if (!set_stack_value (ctx, top, ctx->params [arg], take_addr))
2809 return;
2811 if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC)) {
2812 if (take_addr)
2813 ctx->has_this_store = TRUE;
2814 else
2815 top->stype |= THIS_POINTER_MASK;
2816 if (mono_method_is_constructor (ctx->method) && !ctx->super_ctor_called && !ctx->method->klass->valuetype)
2817 top->stype |= UNINIT_THIS_MASK;
2822 static void
2823 push_local (VerifyContext *ctx, guint32 arg, int take_addr)
2825 if (arg >= ctx->num_locals) {
2826 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local %d", arg + 1));
2827 } else if (check_overflow (ctx)) {
2828 /*We must let the value be pushed, otherwise we would get an underflow error*/
2829 check_unverifiable_type (ctx, ctx->locals [arg]);
2830 if (ctx->locals [arg]->byref && take_addr)
2831 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2833 set_stack_value (ctx, stack_push (ctx), ctx->locals [arg], take_addr);
2837 static void
2838 store_arg (VerifyContext *ctx, guint32 arg)
2840 ILStackDesc *value;
2842 if (arg >= ctx->max_args) {
2843 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", arg + 1, ctx->ip_offset));
2844 if (check_underflow (ctx, 1))
2845 stack_pop (ctx);
2846 return;
2849 if (check_underflow (ctx, 1)) {
2850 value = stack_pop (ctx);
2851 if (!verify_stack_type_compatibility (ctx, ctx->params [arg], value)) {
2852 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in argument store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
2855 if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC))
2856 ctx->has_this_store = 1;
2859 static void
2860 store_local (VerifyContext *ctx, guint32 arg)
2862 ILStackDesc *value;
2863 if (arg >= ctx->num_locals) {
2864 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", arg + 1, ctx->ip_offset));
2865 return;
2868 /*TODO verify definite assigment */
2869 if (!check_underflow (ctx, 1))
2870 return;
2872 value = stack_pop (ctx);
2873 if (ctx->locals [arg]->byref && stack_slot_is_managed_mutability_pointer (value))
2874 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));
2876 if (!verify_stack_type_compatibility (ctx, ctx->locals [arg], value)) {
2877 char *expected = mono_type_full_name (ctx->locals [arg]);
2878 char *found = stack_slot_full_name (value);
2879 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type '%s' on stack cannot be stored to local %d with type '%s' at 0x%04x",
2880 found,
2881 arg,
2882 expected,
2883 ctx->ip_offset));
2884 g_free (expected);
2885 g_free (found);
2889 /*FIXME add and sub needs special care here*/
2890 static void
2891 do_binop (VerifyContext *ctx, unsigned int opcode, const unsigned char table [TYPE_MAX][TYPE_MAX])
2893 ILStackDesc *a, *b, *top;
2894 int idxa, idxb, complexMerge = 0;
2895 unsigned char res;
2897 if (!check_underflow (ctx, 2))
2898 return;
2899 b = stack_pop (ctx);
2900 a = stack_pop (ctx);
2902 idxa = stack_slot_get_underlying_type (a);
2903 if (stack_slot_is_managed_pointer (a)) {
2904 idxa = TYPE_PTR;
2905 complexMerge = 1;
2908 idxb = stack_slot_get_underlying_type (b);
2909 if (stack_slot_is_managed_pointer (b)) {
2910 idxb = TYPE_PTR;
2911 complexMerge = 2;
2914 --idxa;
2915 --idxb;
2916 res = table [idxa][idxb];
2918 VERIFIER_DEBUG ( printf ("binop res %d\n", res); );
2919 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
2921 top = stack_push (ctx);
2922 if (res == TYPE_INV) {
2923 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)));
2924 copy_stack_value (top, a);
2925 return;
2928 if (res & NON_VERIFIABLE_RESULT) {
2929 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)));
2931 res = res & ~NON_VERIFIABLE_RESULT;
2934 if (complexMerge && res == TYPE_PTR) {
2935 if (complexMerge == 1)
2936 copy_stack_value (top, a);
2937 else if (complexMerge == 2)
2938 copy_stack_value (top, b);
2940 * There is no need to merge the type of two pointers.
2941 * The only valid operation is subtraction, that returns a native
2942 * int as result and can be used with any 2 pointer kinds.
2943 * This is valid acording to Patition III 1.1.4
2945 } else
2946 top->stype = res;
2951 static void
2952 do_boolean_branch_op (VerifyContext *ctx, int delta)
2954 int target = ctx->ip_offset + delta;
2955 ILStackDesc *top;
2957 VERIFIER_DEBUG ( printf ("boolean branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
2959 if (target < 0 || target >= ctx->code_size) {
2960 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Boolean branch target out of code at 0x%04x", ctx->ip_offset));
2961 return;
2964 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
2965 case 1:
2966 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2967 break;
2968 case 2:
2969 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2970 return;
2973 ctx->target = target;
2975 if (!check_underflow (ctx, 1))
2976 return;
2978 top = stack_pop (ctx);
2979 if (!is_valid_bool_arg (top))
2980 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));
2982 check_unmanaged_pointer (ctx, top);
2985 static gboolean
2986 stack_slot_is_complex_type_not_reference_type (ILStackDesc *slot)
2988 return stack_slot_get_type (slot) == TYPE_COMPLEX && !MONO_TYPE_IS_REFERENCE (slot->type) && !stack_slot_is_boxed_value (slot);
2991 static gboolean
2992 stack_slot_is_reference_value (ILStackDesc *slot)
2994 return stack_slot_get_type (slot) == TYPE_COMPLEX && (MONO_TYPE_IS_REFERENCE (slot->type) || stack_slot_is_boxed_value (slot));
2997 static void
2998 do_branch_op (VerifyContext *ctx, signed int delta, const unsigned char table [TYPE_MAX][TYPE_MAX])
3000 ILStackDesc *a, *b;
3001 int idxa, idxb;
3002 unsigned char res;
3003 int target = ctx->ip_offset + delta;
3005 VERIFIER_DEBUG ( printf ("branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
3007 if (target < 0 || target >= ctx->code_size) {
3008 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
3009 return;
3012 switch (is_valid_cmp_branch_instruction (ctx->header, ctx->ip_offset, target)) {
3013 case 1: /*FIXME use constants and not magic numbers.*/
3014 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3015 break;
3016 case 2:
3017 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3018 return;
3021 ctx->target = target;
3023 if (!check_underflow (ctx, 2))
3024 return;
3026 b = stack_pop (ctx);
3027 a = stack_pop (ctx);
3029 idxa = stack_slot_get_underlying_type (a);
3030 if (stack_slot_is_managed_pointer (a))
3031 idxa = TYPE_PTR;
3033 idxb = stack_slot_get_underlying_type (b);
3034 if (stack_slot_is_managed_pointer (b))
3035 idxb = TYPE_PTR;
3037 if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
3038 res = TYPE_INV;
3039 } else {
3040 --idxa;
3041 --idxb;
3042 res = table [idxa][idxb];
3045 VERIFIER_DEBUG ( printf ("branch res %d\n", res); );
3046 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
3048 if (res == TYPE_INV) {
3049 CODE_NOT_VERIFIABLE (ctx,
3050 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));
3051 } else if (res & NON_VERIFIABLE_RESULT) {
3052 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));
3053 res = res & ~NON_VERIFIABLE_RESULT;
3057 static void
3058 do_cmp_op (VerifyContext *ctx, const unsigned char table [TYPE_MAX][TYPE_MAX], guint32 opcode)
3060 ILStackDesc *a, *b;
3061 int idxa, idxb;
3062 unsigned char res;
3064 if (!check_underflow (ctx, 2))
3065 return;
3066 b = stack_pop (ctx);
3067 a = stack_pop (ctx);
3069 if (opcode == CEE_CGT_UN) {
3070 if ((stack_slot_is_reference_value (a) && stack_slot_is_null_literal (b)) ||
3071 (stack_slot_is_reference_value (b) && stack_slot_is_null_literal (a))) {
3072 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3073 return;
3077 idxa = stack_slot_get_underlying_type (a);
3078 if (stack_slot_is_managed_pointer (a))
3079 idxa = TYPE_PTR;
3081 idxb = stack_slot_get_underlying_type (b);
3082 if (stack_slot_is_managed_pointer (b))
3083 idxb = TYPE_PTR;
3085 if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
3086 res = TYPE_INV;
3087 } else {
3088 --idxa;
3089 --idxb;
3090 res = table [idxa][idxb];
3093 if(res == TYPE_INV) {
3094 char *left_type = stack_slot_full_name (a);
3095 char *right_type = stack_slot_full_name (b);
3096 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));
3097 g_free (left_type);
3098 g_free (right_type);
3099 } else if (res & NON_VERIFIABLE_RESULT) {
3100 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));
3101 res = res & ~NON_VERIFIABLE_RESULT;
3103 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3106 static void
3107 do_ret (VerifyContext *ctx)
3109 MonoType *ret = ctx->signature->ret;
3110 VERIFIER_DEBUG ( printf ("checking ret\n"); );
3111 if (ret->type != MONO_TYPE_VOID) {
3112 ILStackDesc *top;
3113 if (!check_underflow (ctx, 1))
3114 return;
3116 top = stack_pop(ctx);
3118 if (!verify_stack_type_compatibility (ctx, ctx->signature->ret, top)) {
3119 char *ret_type = mono_type_full_name (ctx->signature->ret);
3120 char *stack_type = stack_slot_full_name (top);
3121 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));
3122 g_free (stack_type);
3123 g_free (ret_type);
3124 return;
3127 if (ret->byref || ret->type == MONO_TYPE_TYPEDBYREF || mono_type_is_value_type (ret, "System", "ArgIterator") || mono_type_is_value_type (ret, "System", "RuntimeArgumentHandle"))
3128 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method returns byref, TypedReference, ArgIterator or RuntimeArgumentHandle at 0x%04x", ctx->ip_offset));
3131 if (ctx->eval.size > 0) {
3132 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack not empty (%d) after ret at 0x%04x", ctx->eval.size, ctx->ip_offset));
3134 if (in_any_block (ctx->header, ctx->ip_offset))
3135 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ret cannot escape exception blocks at 0x%04x", ctx->ip_offset));
3139 * 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.
3140 * This is illegal but mono_get_method_full decoded it.
3141 * TODO handle calling .ctor outside one or calling the .ctor for other class but super
3143 static void
3144 do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual_)
3146 MonoError error;
3147 int param_count, i;
3148 MonoMethodSignature *sig;
3149 ILStackDesc *value;
3150 MonoMethod *method;
3151 gboolean virt_check_this = FALSE;
3152 gboolean constrained = ctx->prefix_set & PREFIX_CONSTRAINED;
3154 if (!(method = verifier_load_method (ctx, method_token, virtual_ ? "callvirt" : "call")))
3155 return;
3157 if (virtual_) {
3158 CLEAR_PREFIX (ctx, PREFIX_CONSTRAINED);
3160 if (method->klass->valuetype) // && !constrained ???
3161 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with valuetype method at 0x%04x", ctx->ip_offset));
3163 if ((method->flags & METHOD_ATTRIBUTE_STATIC))
3164 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with static method at 0x%04x", ctx->ip_offset));
3166 } else {
3167 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
3168 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use call with an abstract method at 0x%04x", ctx->ip_offset));
3170 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !mono_class_is_sealed (method->klass)) {
3171 virt_check_this = TRUE;
3172 ctx->code [ctx->ip_offset].flags |= IL_CODE_CALL_NONFINAL_VIRTUAL;
3176 if (!(sig = mono_method_get_signature_checked (method, ctx->image, method_token, ctx->generic_context, &error))) {
3177 mono_error_cleanup (&error);
3178 sig = mono_method_get_signature_checked (method, ctx->image, method_token, NULL, &error);
3181 if (!sig) {
3182 char *name = mono_type_get_full_name (method->klass);
3183 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)));
3184 mono_error_cleanup (&error);
3185 g_free (name);
3186 return;
3189 param_count = sig->param_count + sig->hasthis;
3190 if (!check_underflow (ctx, param_count))
3191 return;
3193 for (i = sig->param_count - 1; i >= 0; --i) {
3194 VERIFIER_DEBUG ( printf ("verifying argument %d\n", i); );
3195 value = stack_pop (ctx);
3196 if (!verify_stack_type_compatibility (ctx, sig->params[i], value)) {
3197 char *stack_name = stack_slot_full_name (value);
3198 char *sig_name = mono_type_full_name (sig->params [i]);
3199 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));
3200 g_free (stack_name);
3201 g_free (sig_name);
3204 if (stack_slot_is_managed_mutability_pointer (value))
3205 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));
3207 if ((ctx->prefix_set & PREFIX_TAIL) && stack_slot_is_managed_pointer (value)) {
3208 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));
3209 return;
3213 if (sig->hasthis) {
3214 MonoType *type = &method->klass->byval_arg;
3215 ILStackDesc copy;
3217 if (mono_method_is_constructor (method) && !method->klass->valuetype) {
3218 if (IS_STRICT_MODE (ctx) && !mono_method_is_constructor (ctx->method))
3219 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor outside one at 0x%04x", ctx->ip_offset));
3220 if (IS_STRICT_MODE (ctx) && method->klass != ctx->method->klass->parent && method->klass != ctx->method->klass)
3221 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));
3223 ctx->super_ctor_called = TRUE;
3224 value = stack_pop_safe (ctx);
3225 if (IS_STRICT_MODE (ctx) && (value->stype & THIS_POINTER_MASK) != THIS_POINTER_MASK)
3226 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid 'this ptr' argument for constructor at 0x%04x", ctx->ip_offset));
3227 } else {
3228 value = stack_pop (ctx);
3231 copy_stack_value (&copy, value);
3232 //TODO we should extract this to a 'drop_byref_argument' and use everywhere
3233 //Other parts of the code suffer from the same issue of
3234 copy.type = mono_type_get_type_byval (copy.type);
3235 copy.stype &= ~POINTER_MASK;
3237 if (virt_check_this && !stack_slot_is_this_pointer (value) && !(method->klass->valuetype || stack_slot_is_boxed_value (value)))
3238 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));
3240 if (constrained && virtual_) {
3241 if (!stack_slot_is_managed_pointer (value))
3242 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object is not a managed pointer for a constrained call at 0x%04x", ctx->ip_offset));
3243 if (!mono_metadata_type_equal_full (mono_type_get_type_byval (value->type), mono_type_get_underlying_type (ctx->constrained_type), TRUE))
3244 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object not compatible with constrained type at 0x%04x", ctx->ip_offset));
3245 copy.stype |= BOXED_MASK;
3246 copy.type = ctx->constrained_type;
3247 } else {
3248 if (stack_slot_is_managed_pointer (value) && !mono_class_from_mono_type (value->type)->valuetype)
3249 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));
3251 if (!virtual_ && mono_class_from_mono_type (value->type)->valuetype && !method->klass->valuetype && !stack_slot_is_boxed_value (value))
3252 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a valuetype baseclass at 0x%04x", ctx->ip_offset));
3254 if (virtual_ && mono_class_from_mono_type (value->type)->valuetype && !stack_slot_is_boxed_value (value))
3255 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a valuetype with callvirt at 0x%04x", ctx->ip_offset));
3257 if (method->klass->valuetype && (stack_slot_is_boxed_value (value) || !stack_slot_is_managed_pointer (value)))
3258 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));
3260 if (!verify_stack_type_compatibility (ctx, type, &copy)) {
3261 char *expected = mono_type_full_name (type);
3262 char *effective = stack_slot_full_name (&copy);
3263 char *method_name = mono_method_full_name (method, TRUE);
3264 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",
3265 expected, effective, method_name, ctx->ip_offset));
3266 g_free (method_name);
3267 g_free (effective);
3268 g_free (expected);
3271 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, mono_class_from_mono_type (value->type))) {
3272 char *name = mono_method_full_name (method, TRUE);
3273 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3274 g_free (name);
3277 } else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
3278 char *name = mono_method_full_name (method, TRUE);
3279 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3280 g_free (name);
3283 if (sig->ret->type != MONO_TYPE_VOID) {
3284 if (!mono_type_is_valid_in_context (ctx, sig->ret))
3285 return;
3287 if (check_overflow (ctx)) {
3288 value = stack_push (ctx);
3289 set_stack_value (ctx, value, sig->ret, FALSE);
3290 if ((ctx->prefix_set & PREFIX_READONLY) && method->klass->rank && !strcmp (method->name, "Address")) {
3291 ctx->prefix_set &= ~PREFIX_READONLY;
3292 value->stype |= CMMP_MASK;
3297 if ((ctx->prefix_set & PREFIX_TAIL)) {
3298 if (!mono_delegate_ret_equal (mono_method_signature (ctx->method)->ret, sig->ret))
3299 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call with incompatible return type at 0x%04x", ctx->ip_offset));
3300 if (ctx->header->code [ctx->ip_offset + 5] != CEE_RET)
3301 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call not followed by ret at 0x%04x", ctx->ip_offset));
3306 static void
3307 do_push_static_field (VerifyContext *ctx, int token, gboolean take_addr)
3309 MonoClassField *field;
3310 MonoClass *klass;
3311 if (!check_overflow (ctx))
3312 return;
3313 if (!take_addr)
3314 CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3316 if (!(field = verifier_load_field (ctx, token, &klass, take_addr ? "ldsflda" : "ldsfld")))
3317 return;
3319 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3320 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load non static field at 0x%04x", ctx->ip_offset));
3321 return;
3323 /*taking the address of initonly field only works from the static constructor */
3324 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3325 !(field->parent == ctx->method->klass && (ctx->method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_STATIC)) && !strcmp (".cctor", ctx->method->name)))
3326 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
3328 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3329 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3331 set_stack_value (ctx, stack_push (ctx), field->type, take_addr);
3334 static void
3335 do_store_static_field (VerifyContext *ctx, int token) {
3336 MonoClassField *field;
3337 MonoClass *klass;
3338 ILStackDesc *value;
3339 CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3341 if (!check_underflow (ctx, 1))
3342 return;
3344 value = stack_pop (ctx);
3346 if (!(field = verifier_load_field (ctx, token, &klass, "stsfld")))
3347 return;
3349 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3350 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store non static field at 0x%04x", ctx->ip_offset));
3351 return;
3354 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3355 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type in store static field at 0x%04x", ctx->ip_offset));
3356 return;
3359 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3360 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3362 if (!verify_stack_type_compatibility (ctx, field->type, value)) {
3363 char *stack_name = stack_slot_full_name (value);
3364 char *field_name = mono_type_full_name (field->type);
3365 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type in static field store expected '%s' but found '%s' at 0x%04x",
3366 field_name, stack_name, ctx->ip_offset));
3367 g_free (field_name);
3368 g_free (stack_name);
3372 static gboolean
3373 check_is_valid_type_for_field_ops (VerifyContext *ctx, int token, ILStackDesc *obj, MonoClassField **ret_field, const char *opcode)
3375 MonoClassField *field;
3376 MonoClass *klass;
3377 gboolean is_pointer;
3379 /*must be a reference type, a managed pointer, an unamanaged pointer, or a valuetype*/
3380 if (!(field = verifier_load_field (ctx, token, &klass, opcode)))
3381 return FALSE;
3383 *ret_field = field;
3384 //the value on stack is going to be used as a pointer
3385 is_pointer = stack_slot_get_type (obj) == TYPE_PTR || (stack_slot_get_type (obj) == TYPE_NATIVE_INT && !get_stack_type (&field->parent->byval_arg));
3387 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3388 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type at 0x%04x", ctx->ip_offset));
3389 return FALSE;
3391 g_assert (obj->type);
3393 /*The value on the stack must be a subclass of the defining type of the field*/
3394 /* we need to check if we can load the field from the stack value*/
3395 if (is_pointer) {
3396 if (stack_slot_get_underlying_type (obj) == TYPE_NATIVE_INT)
3397 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Native int is not a verifiable type to reference a field at 0x%04x", ctx->ip_offset));
3399 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3400 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3401 } else {
3402 if (!field->parent->valuetype && stack_slot_is_managed_pointer (obj))
3403 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));
3405 /*a value type can be loaded from a value or a managed pointer, but not a boxed object*/
3406 if (field->parent->valuetype && stack_slot_is_boxed_value (obj))
3407 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));
3409 if (!stack_slot_is_null_literal (obj) && !verify_stack_type_compatibility_full (ctx, &field->parent->byval_arg, obj, TRUE, FALSE)) {
3410 char *found = stack_slot_full_name (obj);
3411 char *expected = mono_type_full_name (&field->parent->byval_arg);
3412 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));
3413 g_free (found);
3414 g_free (expected);
3417 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, mono_class_from_mono_type (obj->type)))
3418 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3421 check_unmanaged_pointer (ctx, obj);
3422 return TRUE;
3425 static void
3426 do_push_field (VerifyContext *ctx, int token, gboolean take_addr)
3428 ILStackDesc *obj;
3429 MonoClassField *field;
3431 if (!take_addr)
3432 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3434 if (!check_underflow (ctx, 1))
3435 return;
3436 obj = stack_pop_safe (ctx);
3438 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, take_addr ? "ldflda" : "ldfld"))
3439 return;
3441 if (take_addr && field->parent->valuetype && !stack_slot_is_managed_pointer (obj))
3442 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a temporary value-type at 0x%04x", ctx->ip_offset));
3444 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3445 !(field->parent == ctx->method->klass && mono_method_is_constructor (ctx->method)))
3446 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
3448 set_stack_value (ctx, stack_push (ctx), field->type, take_addr);
3451 static void
3452 do_store_field (VerifyContext *ctx, int token)
3454 ILStackDesc *value, *obj;
3455 MonoClassField *field;
3456 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3458 if (!check_underflow (ctx, 2))
3459 return;
3461 value = stack_pop (ctx);
3462 obj = stack_pop_safe (ctx);
3464 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, "stfld"))
3465 return;
3467 if (!verify_stack_type_compatibility (ctx, field->type, value))
3468 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in field store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3471 /*TODO proper handle for Nullable<T>*/
3472 static void
3473 do_box_value (VerifyContext *ctx, int klass_token)
3475 ILStackDesc *value;
3476 MonoType *type = get_boxable_mono_type (ctx, klass_token, "box");
3477 MonoClass *klass;
3479 if (!type)
3480 return;
3482 if (!check_underflow (ctx, 1))
3483 return;
3485 value = stack_pop (ctx);
3486 /*box is a nop for reference types*/
3488 if (stack_slot_get_underlying_type (value) == TYPE_COMPLEX && MONO_TYPE_IS_REFERENCE (value->type) && MONO_TYPE_IS_REFERENCE (type)) {
3489 stack_push_stack_val (ctx, value)->stype |= BOXED_MASK;
3490 return;
3494 if (!verify_stack_type_compatibility (ctx, type, value))
3495 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for boxing operation at 0x%04x", ctx->ip_offset));
3497 klass = mono_class_from_mono_type (type);
3498 if (mono_class_is_nullable (klass))
3499 type = &mono_class_get_nullable_param (klass)->byval_arg;
3500 stack_push_val (ctx, TYPE_COMPLEX | BOXED_MASK, type);
3503 static void
3504 do_unbox_value (VerifyContext *ctx, int klass_token)
3506 ILStackDesc *value;
3507 MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox");
3509 if (!type)
3510 return;
3512 if (!check_underflow (ctx, 1))
3513 return;
3515 if (!mono_class_from_mono_type (type)->valuetype)
3516 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid reference type for unbox at 0x%04x", ctx->ip_offset));
3518 value = stack_pop (ctx);
3520 /*Value should be: a boxed valuetype or a reference type*/
3521 if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3522 (stack_slot_is_boxed_value (value) || !mono_class_from_mono_type (value->type)->valuetype)))
3523 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));
3525 set_stack_value (ctx, value = stack_push (ctx), mono_type_get_type_byref (type), FALSE);
3526 value->stype |= CMMP_MASK;
3529 static void
3530 do_unbox_any (VerifyContext *ctx, int klass_token)
3532 ILStackDesc *value;
3533 MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox.any");
3535 if (!type)
3536 return;
3538 if (!check_underflow (ctx, 1))
3539 return;
3541 value = stack_pop (ctx);
3543 /*Value should be: a boxed valuetype or a reference type*/
3544 if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3545 (stack_slot_is_boxed_value (value) || !mono_class_from_mono_type (value->type)->valuetype)))
3546 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));
3548 set_stack_value (ctx, stack_push (ctx), type, FALSE);
3551 static void
3552 do_unary_math_op (VerifyContext *ctx, int op)
3554 ILStackDesc *value;
3555 if (!check_underflow (ctx, 1))
3556 return;
3557 value = stack_pop (ctx);
3558 switch (stack_slot_get_type (value)) {
3559 case TYPE_I4:
3560 case TYPE_I8:
3561 case TYPE_NATIVE_INT:
3562 break;
3563 case TYPE_R8:
3564 if (op == CEE_NEG)
3565 break;
3566 case TYPE_COMPLEX: /*only enums are ok*/
3567 if (mono_type_is_enum_type (value->type))
3568 break;
3569 default:
3570 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for unary not at 0x%04x", ctx->ip_offset));
3572 stack_push_stack_val (ctx, value);
3575 static void
3576 do_conversion (VerifyContext *ctx, int kind)
3578 ILStackDesc *value;
3579 if (!check_underflow (ctx, 1))
3580 return;
3581 value = stack_pop (ctx);
3583 switch (stack_slot_get_type (value)) {
3584 case TYPE_I4:
3585 case TYPE_I8:
3586 case TYPE_NATIVE_INT:
3587 case TYPE_R8:
3588 break;
3589 default:
3590 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));
3593 switch (kind) {
3594 case TYPE_I4:
3595 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3596 break;
3597 case TYPE_I8:
3598 stack_push_val (ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
3599 break;
3600 case TYPE_R8:
3601 stack_push_val (ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
3602 break;
3603 case TYPE_NATIVE_INT:
3604 stack_push_val (ctx, TYPE_NATIVE_INT, &mono_defaults.int_class->byval_arg);
3605 break;
3606 default:
3607 g_error ("unknown type %02x in conversion", kind);
3612 static void
3613 do_load_token (VerifyContext *ctx, int token)
3615 MonoError error;
3616 gpointer handle;
3617 MonoClass *handle_class;
3618 if (!check_overflow (ctx))
3619 return;
3621 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
3622 handle = mono_method_get_wrapper_data (ctx->method, token);
3623 handle_class = (MonoClass *)mono_method_get_wrapper_data (ctx->method, token + 1);
3624 if (handle_class == mono_defaults.typehandle_class)
3625 handle = &((MonoClass*)handle)->byval_arg;
3626 } else {
3627 switch (token & 0xff000000) {
3628 case MONO_TOKEN_TYPE_DEF:
3629 case MONO_TOKEN_TYPE_REF:
3630 case MONO_TOKEN_TYPE_SPEC:
3631 case MONO_TOKEN_FIELD_DEF:
3632 case MONO_TOKEN_METHOD_DEF:
3633 case MONO_TOKEN_METHOD_SPEC:
3634 case MONO_TOKEN_MEMBER_REF:
3635 if (!token_bounds_check (ctx->image, token)) {
3636 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));
3637 return;
3639 break;
3640 default:
3641 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));
3642 return;
3645 handle = mono_ldtoken_checked (ctx->image, token, &handle_class, ctx->generic_context, &error);
3648 if (!handle) {
3649 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)));
3650 mono_error_cleanup (&error);
3651 return;
3653 if (handle_class == mono_defaults.typehandle_class) {
3654 mono_type_is_valid_in_context (ctx, (MonoType*)handle);
3655 } else if (handle_class == mono_defaults.methodhandle_class) {
3656 mono_method_is_valid_in_context (ctx, (MonoMethod*)handle);
3657 } else if (handle_class == mono_defaults.fieldhandle_class) {
3658 mono_type_is_valid_in_context (ctx, &((MonoClassField*)handle)->parent->byval_arg);
3659 } else {
3660 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid ldtoken type %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
3662 stack_push_val (ctx, TYPE_COMPLEX, mono_class_get_type (handle_class));
3665 static void
3666 do_ldobj_value (VerifyContext *ctx, int token)
3668 ILStackDesc *value;
3669 MonoType *type = get_boxable_mono_type (ctx, token, "ldobj");
3670 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3672 if (!type)
3673 return;
3675 if (!check_underflow (ctx, 1))
3676 return;
3678 value = stack_pop (ctx);
3679 if (!stack_slot_is_managed_pointer (value)
3680 && stack_slot_get_type (value) != TYPE_NATIVE_INT
3681 && !(stack_slot_get_type (value) == TYPE_PTR && value->type->type != MONO_TYPE_FNPTR)) {
3682 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid argument %s to ldobj at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3683 return;
3686 if (stack_slot_get_type (value) == TYPE_NATIVE_INT)
3687 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Using native pointer to ldobj at 0x%04x", ctx->ip_offset));
3689 /*We have a byval on the stack, but the comparison must be strict. */
3690 if (!verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (value->type), TRUE))
3691 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldojb operation at 0x%04x", ctx->ip_offset));
3693 set_stack_value (ctx, stack_push (ctx), type, FALSE);
3696 static void
3697 do_stobj (VerifyContext *ctx, int token)
3699 ILStackDesc *dest, *src;
3700 MonoType *type = get_boxable_mono_type (ctx, token, "stobj");
3701 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3703 if (!type)
3704 return;
3706 if (!check_underflow (ctx, 2))
3707 return;
3709 src = stack_pop (ctx);
3710 dest = stack_pop (ctx);
3712 if (stack_slot_is_managed_mutability_pointer (dest))
3713 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stobj at 0x%04x", ctx->ip_offset));
3715 if (!stack_slot_is_managed_pointer (dest))
3716 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of stobj operation at 0x%04x", ctx->ip_offset));
3718 if (stack_slot_is_boxed_value (src) && !MONO_TYPE_IS_REFERENCE (src->type) && !MONO_TYPE_IS_REFERENCE (type))
3719 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));
3721 if (!verify_stack_type_compatibility (ctx, type, src)) {
3722 char *type_name = mono_type_full_name (type);
3723 char *src_name = stack_slot_full_name (src);
3724 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));
3725 g_free (type_name);
3726 g_free (src_name);
3729 if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3730 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of stobj don't match at 0x%04x", ctx->ip_offset));
3733 static void
3734 do_cpobj (VerifyContext *ctx, int token)
3736 ILStackDesc *dest, *src;
3737 MonoType *type = get_boxable_mono_type (ctx, token, "cpobj");
3738 if (!type)
3739 return;
3741 if (!check_underflow (ctx, 2))
3742 return;
3744 src = stack_pop (ctx);
3745 dest = stack_pop (ctx);
3747 if (!stack_slot_is_managed_pointer (src))
3748 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid source of cpobj operation at 0x%04x", ctx->ip_offset));
3750 if (!stack_slot_is_managed_pointer (dest))
3751 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of cpobj operation at 0x%04x", ctx->ip_offset));
3753 if (stack_slot_is_managed_mutability_pointer (dest))
3754 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with cpobj at 0x%04x", ctx->ip_offset));
3756 if (!verify_type_compatibility (ctx, type, mono_type_get_type_byval (src->type)))
3757 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Token and source types of cpobj don't match at 0x%04x", ctx->ip_offset));
3759 if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3760 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of cpobj don't match at 0x%04x", ctx->ip_offset));
3763 static void
3764 do_initobj (VerifyContext *ctx, int token)
3766 ILStackDesc *obj;
3767 MonoType *stack, *type = get_boxable_mono_type (ctx, token, "initobj");
3768 if (!type)
3769 return;
3771 if (!check_underflow (ctx, 1))
3772 return;
3774 obj = stack_pop (ctx);
3776 if (!stack_slot_is_managed_pointer (obj))
3777 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid object address for initobj at 0x%04x", ctx->ip_offset));
3779 if (stack_slot_is_managed_mutability_pointer (obj))
3780 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with initobj at 0x%04x", ctx->ip_offset));
3782 stack = mono_type_get_type_byval (obj->type);
3783 if (MONO_TYPE_IS_REFERENCE (stack)) {
3784 if (!verify_type_compatibility (ctx, stack, type))
3785 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3786 else if (IS_STRICT_MODE (ctx) && !mono_metadata_type_equal (type, stack))
3787 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3788 } else if (!verify_type_compatibility (ctx, stack, type)) {
3789 char *expected_name = mono_type_full_name (type);
3790 char *stack_name = mono_type_full_name (stack);
3792 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));
3793 g_free (expected_name);
3794 g_free (stack_name);
3798 static void
3799 do_newobj (VerifyContext *ctx, int token)
3801 ILStackDesc *value;
3802 int i;
3803 MonoMethodSignature *sig;
3804 MonoMethod *method;
3805 gboolean is_delegate = FALSE;
3807 if (!(method = verifier_load_method (ctx, token, "newobj")))
3808 return;
3810 if (!mono_method_is_constructor (method)) {
3811 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method from token 0x%08x not a constructor at 0x%04x", token, ctx->ip_offset));
3812 return;
3815 if (mono_class_get_flags (method->klass) & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE))
3816 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Trying to instantiate an abstract or interface type at 0x%04x", ctx->ip_offset));
3818 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
3819 char *from = mono_method_full_name (ctx->method, TRUE);
3820 char *to = mono_method_full_name (method, TRUE);
3821 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);
3822 g_free (from);
3823 g_free (to);
3826 //FIXME use mono_method_get_signature_full
3827 sig = mono_method_signature (method);
3828 if (!sig) {
3829 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid constructor signature to newobj at 0x%04x", ctx->ip_offset));
3830 return;
3833 if (!sig->hasthis) {
3834 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid constructor signature missing hasthis at 0x%04x", ctx->ip_offset));
3835 return;
3838 if (!check_underflow (ctx, sig->param_count))
3839 return;
3841 is_delegate = method->klass->parent == mono_defaults.multicastdelegate_class;
3843 if (is_delegate) {
3844 ILStackDesc *funptr;
3845 //first arg is object, second arg is fun ptr
3846 if (sig->param_count != 2) {
3847 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid delegate constructor at 0x%04x", ctx->ip_offset));
3848 return;
3850 funptr = stack_pop (ctx);
3851 value = stack_pop (ctx);
3852 verify_delegate_compatibility (ctx, method->klass, value, funptr);
3853 } else {
3854 for (i = sig->param_count - 1; i >= 0; --i) {
3855 VERIFIER_DEBUG ( printf ("verifying constructor argument %d\n", i); );
3856 value = stack_pop (ctx);
3857 if (!verify_stack_type_compatibility (ctx, sig->params [i], value)) {
3858 char *stack_name = stack_slot_full_name (value);
3859 char *sig_name = mono_type_full_name (sig->params [i]);
3860 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));
3861 g_free (stack_name);
3862 g_free (sig_name);
3865 if (stack_slot_is_managed_mutability_pointer (value))
3866 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer as argument of newobj at 0x%04x", ctx->ip_offset));
3870 if (check_overflow (ctx))
3871 set_stack_value (ctx, stack_push (ctx), &method->klass->byval_arg, FALSE);
3874 static void
3875 do_cast (VerifyContext *ctx, int token, const char *opcode) {
3876 ILStackDesc *value;
3877 MonoType *type;
3878 gboolean is_boxed;
3879 gboolean do_box;
3881 if (!check_underflow (ctx, 1))
3882 return;
3884 if (!(type = get_boxable_mono_type (ctx, token, opcode)))
3885 return;
3887 if (type->byref) {
3888 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid %s type at 0x%04x", opcode, ctx->ip_offset));
3889 return;
3892 value = stack_pop (ctx);
3893 is_boxed = stack_slot_is_boxed_value (value);
3895 if (stack_slot_is_managed_pointer (value))
3896 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
3897 else if (!MONO_TYPE_IS_REFERENCE (value->type) && !is_boxed) {
3898 char *name = stack_slot_full_name (value);
3899 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));
3900 g_free (name);
3903 switch (value->type->type) {
3904 case MONO_TYPE_FNPTR:
3905 case MONO_TYPE_PTR:
3906 case MONO_TYPE_TYPEDBYREF:
3907 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
3908 default:
3909 break;
3912 do_box = is_boxed || mono_type_is_generic_argument(type) || mono_class_from_mono_type (type)->valuetype;
3913 stack_push_val (ctx, TYPE_COMPLEX | (do_box ? BOXED_MASK : 0), type);
3916 static MonoType *
3917 mono_type_from_opcode (int opcode) {
3918 switch (opcode) {
3919 case CEE_LDIND_I1:
3920 case CEE_LDIND_U1:
3921 case CEE_STIND_I1:
3922 case CEE_LDELEM_I1:
3923 case CEE_LDELEM_U1:
3924 case CEE_STELEM_I1:
3925 return &mono_defaults.sbyte_class->byval_arg;
3927 case CEE_LDIND_I2:
3928 case CEE_LDIND_U2:
3929 case CEE_STIND_I2:
3930 case CEE_LDELEM_I2:
3931 case CEE_LDELEM_U2:
3932 case CEE_STELEM_I2:
3933 return &mono_defaults.int16_class->byval_arg;
3935 case CEE_LDIND_I4:
3936 case CEE_LDIND_U4:
3937 case CEE_STIND_I4:
3938 case CEE_LDELEM_I4:
3939 case CEE_LDELEM_U4:
3940 case CEE_STELEM_I4:
3941 return &mono_defaults.int32_class->byval_arg;
3943 case CEE_LDIND_I8:
3944 case CEE_STIND_I8:
3945 case CEE_LDELEM_I8:
3946 case CEE_STELEM_I8:
3947 return &mono_defaults.int64_class->byval_arg;
3949 case CEE_LDIND_R4:
3950 case CEE_STIND_R4:
3951 case CEE_LDELEM_R4:
3952 case CEE_STELEM_R4:
3953 return &mono_defaults.single_class->byval_arg;
3955 case CEE_LDIND_R8:
3956 case CEE_STIND_R8:
3957 case CEE_LDELEM_R8:
3958 case CEE_STELEM_R8:
3959 return &mono_defaults.double_class->byval_arg;
3961 case CEE_LDIND_I:
3962 case CEE_STIND_I:
3963 case CEE_LDELEM_I:
3964 case CEE_STELEM_I:
3965 return &mono_defaults.int_class->byval_arg;
3967 case CEE_LDIND_REF:
3968 case CEE_STIND_REF:
3969 case CEE_LDELEM_REF:
3970 case CEE_STELEM_REF:
3971 return &mono_defaults.object_class->byval_arg;
3973 default:
3974 g_error ("unknown opcode %02x in mono_type_from_opcode ", opcode);
3975 return NULL;
3979 static void
3980 do_load_indirect (VerifyContext *ctx, int opcode)
3982 ILStackDesc *value;
3983 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3985 if (!check_underflow (ctx, 1))
3986 return;
3988 value = stack_pop (ctx);
3989 if (!stack_slot_is_managed_pointer (value)) {
3990 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Load indirect not using a manager pointer at 0x%04x", ctx->ip_offset));
3991 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
3992 return;
3995 if (opcode == CEE_LDIND_REF) {
3996 if (stack_slot_get_underlying_type (value) != TYPE_COMPLEX || mono_class_from_mono_type (value->type)->valuetype)
3997 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind_ref expected object byref operation at 0x%04x", ctx->ip_offset));
3998 set_stack_value (ctx, stack_push (ctx), mono_type_get_type_byval (value->type), FALSE);
3999 } else {
4000 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (value->type), TRUE))
4001 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4002 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
4006 static void
4007 do_store_indirect (VerifyContext *ctx, int opcode)
4009 ILStackDesc *addr, *val;
4010 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
4012 if (!check_underflow (ctx, 2))
4013 return;
4015 val = stack_pop (ctx);
4016 addr = stack_pop (ctx);
4018 check_unmanaged_pointer (ctx, addr);
4020 if (!stack_slot_is_managed_pointer (addr) && stack_slot_get_type (addr) != TYPE_PTR) {
4021 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid non-pointer argument to stind at 0x%04x", ctx->ip_offset));
4022 return;
4025 if (stack_slot_is_managed_mutability_pointer (addr)) {
4026 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stind at 0x%04x", ctx->ip_offset));
4027 return;
4030 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (addr->type), TRUE))
4031 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid addr type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4033 if (!verify_stack_type_compatibility (ctx, mono_type_from_opcode (opcode), val))
4034 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4037 static void
4038 do_newarr (VerifyContext *ctx, int token)
4040 ILStackDesc *value;
4041 MonoType *type = get_boxable_mono_type (ctx, token, "newarr");
4043 if (!type)
4044 return;
4046 if (!check_underflow (ctx, 1))
4047 return;
4049 value = stack_pop (ctx);
4050 if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
4051 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));
4053 set_stack_value (ctx, stack_push (ctx), mono_class_get_type (mono_array_class_get (mono_class_from_mono_type (type), 1)), FALSE);
4056 /*FIXME handle arrays that are not 0-indexed*/
4057 static void
4058 do_ldlen (VerifyContext *ctx)
4060 ILStackDesc *value;
4062 if (!check_underflow (ctx, 1))
4063 return;
4065 value = stack_pop (ctx);
4067 if (stack_slot_get_type (value) != TYPE_COMPLEX || value->type->type != MONO_TYPE_SZARRAY)
4068 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type for ldlen at 0x%04x", ctx->ip_offset));
4070 stack_push_val (ctx, TYPE_NATIVE_INT, &mono_defaults.int_class->byval_arg);
4073 /*FIXME handle arrays that are not 0-indexed*/
4074 /*FIXME handle readonly prefix and CMMP*/
4075 static void
4076 do_ldelema (VerifyContext *ctx, int klass_token)
4078 ILStackDesc *index, *array, *res;
4079 MonoType *type = get_boxable_mono_type (ctx, klass_token, "ldelema");
4080 gboolean valid;
4082 if (!type)
4083 return;
4085 if (!check_underflow (ctx, 2))
4086 return;
4088 index = stack_pop (ctx);
4089 array = stack_pop (ctx);
4091 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4092 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));
4094 if (!stack_slot_is_null_literal (array)) {
4095 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
4096 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type(%s) for ldelema at 0x%04x", stack_slot_get_name (array), ctx->ip_offset));
4097 else {
4098 if (get_stack_type (type) == TYPE_I4 || get_stack_type (type) == TYPE_NATIVE_INT) {
4099 valid = verify_type_compatibility_full (ctx, type, &array->type->data.klass->byval_arg, TRUE);
4100 } else {
4101 valid = mono_metadata_type_equal (type, &array->type->data.klass->byval_arg);
4103 if (!valid)
4104 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelema at 0x%04x", ctx->ip_offset));
4108 res = stack_push (ctx);
4109 set_stack_value (ctx, res, type, TRUE);
4110 if (ctx->prefix_set & PREFIX_READONLY) {
4111 ctx->prefix_set &= ~PREFIX_READONLY;
4112 res->stype |= CMMP_MASK;
4117 * FIXME handle arrays that are not 0-indexed
4118 * FIXME handle readonly prefix and CMMP
4120 static void
4121 do_ldelem (VerifyContext *ctx, int opcode, int token)
4123 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
4124 ILStackDesc *index, *array;
4125 MonoType *type;
4126 if (!check_underflow (ctx, 2))
4127 return;
4129 if (opcode == CEE_LDELEM) {
4130 if (!(type = verifier_load_type (ctx, token, "ldelem.any"))) {
4131 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
4132 return;
4134 } else {
4135 type = mono_type_from_opcode (opcode);
4138 index = stack_pop (ctx);
4139 array = stack_pop (ctx);
4141 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4142 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));
4144 if (!stack_slot_is_null_literal (array)) {
4145 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
4146 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));
4147 else {
4148 if (opcode == CEE_LDELEM_REF) {
4149 if (array->type->data.klass->valuetype)
4150 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for ldelem.ref 0x%04x", ctx->ip_offset));
4151 type = &array->type->data.klass->byval_arg;
4152 } else {
4153 MonoType *candidate = &array->type->data.klass->byval_arg;
4154 if (IS_STRICT_MODE (ctx)) {
4155 MonoType *underlying_type = mono_type_get_underlying_type_any (type);
4156 MonoType *underlying_candidate = mono_type_get_underlying_type_any (candidate);
4157 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)) ||
4158 (IS_ONE_OF2 (underlying_candidate->type, MONO_TYPE_I4, MONO_TYPE_U4) && IS_ONE_OF2 (underlying_type->type, MONO_TYPE_I, MONO_TYPE_U)))
4159 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
4161 if (!verify_type_compatibility_full (ctx, type, candidate, TRUE))
4162 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
4167 set_stack_value (ctx, stack_push (ctx), type, FALSE);
4168 #undef IS_ONE_OF2
4172 * FIXME handle arrays that are not 0-indexed
4174 static void
4175 do_stelem (VerifyContext *ctx, int opcode, int token)
4177 ILStackDesc *index, *array, *value;
4178 MonoType *type;
4179 if (!check_underflow (ctx, 3))
4180 return;
4182 if (opcode == CEE_STELEM) {
4183 if (!(type = verifier_load_type (ctx, token, "stelem.any"))) {
4184 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
4185 return;
4187 } else {
4188 type = mono_type_from_opcode (opcode);
4191 value = stack_pop (ctx);
4192 index = stack_pop (ctx);
4193 array = stack_pop (ctx);
4195 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4196 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));
4198 if (!stack_slot_is_null_literal (array)) {
4199 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY) {
4200 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));
4201 } else {
4202 if (opcode == CEE_STELEM_REF) {
4203 if (array->type->data.klass->valuetype)
4204 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4205 } else if (!verify_type_compatibility_full (ctx, &array->type->data.klass->byval_arg, type, TRUE)) {
4206 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4210 if (opcode == CEE_STELEM_REF) {
4211 if (!stack_slot_is_boxed_value (value) && mono_class_from_mono_type (value->type)->valuetype)
4212 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4213 } else if (opcode != CEE_STELEM_REF) {
4214 if (!verify_stack_type_compatibility (ctx, type, value))
4215 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4217 if (stack_slot_is_boxed_value (value) && !MONO_TYPE_IS_REFERENCE (value->type) && !MONO_TYPE_IS_REFERENCE (type))
4218 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));
4223 static void
4224 do_throw (VerifyContext *ctx)
4226 ILStackDesc *exception;
4227 if (!check_underflow (ctx, 1))
4228 return;
4229 exception = stack_pop (ctx);
4231 if (!stack_slot_is_null_literal (exception) && !(stack_slot_get_type (exception) == TYPE_COMPLEX && !mono_class_from_mono_type (exception->type)->valuetype))
4232 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type on stack for throw, expected reference type at 0x%04x", ctx->ip_offset));
4234 if (mono_type_is_generic_argument (exception->type) && !stack_slot_is_boxed_value (exception)) {
4235 char *name = mono_type_full_name (exception->type);
4236 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));
4237 g_free (name);
4239 /*The stack is left empty after a throw*/
4240 ctx->eval.size = 0;
4244 static void
4245 do_endfilter (VerifyContext *ctx)
4247 MonoExceptionClause *clause;
4249 if (IS_STRICT_MODE (ctx)) {
4250 if (ctx->eval.size != 1)
4251 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack size must have one item for endfilter at 0x%04x", ctx->ip_offset));
4253 if (ctx->eval.size >= 1 && stack_slot_get_type (stack_pop (ctx)) != TYPE_I4)
4254 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack item type is not an int32 for endfilter at 0x%04x", ctx->ip_offset));
4257 if ((clause = is_correct_endfilter (ctx, ctx->ip_offset))) {
4258 if (IS_STRICT_MODE (ctx)) {
4259 if (ctx->ip_offset != clause->handler_offset - 2)
4260 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
4261 } else {
4262 if ((ctx->ip_offset != clause->handler_offset - 2) && !MONO_OFFSET_IN_HANDLER (clause, ctx->ip_offset))
4263 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
4265 } else {
4266 if (IS_STRICT_MODE (ctx) && !is_unverifiable_endfilter (ctx, ctx->ip_offset))
4267 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4268 else
4269 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4272 ctx->eval.size = 0;
4275 static void
4276 do_leave (VerifyContext *ctx, int delta)
4278 int target = ((gint32)ctx->ip_offset) + delta;
4279 if (target >= ctx->code_size || target < 0)
4280 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
4282 if (!is_correct_leave (ctx->header, ctx->ip_offset, target))
4283 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ctx->ip_offset));
4284 ctx->eval.size = 0;
4285 ctx->target = target;
4289 * do_static_branch:
4291 * Verify br and br.s opcodes.
4293 static void
4294 do_static_branch (VerifyContext *ctx, int delta)
4296 int target = ctx->ip_offset + delta;
4297 if (target < 0 || target >= ctx->code_size) {
4298 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("branch target out of code at 0x%04x", ctx->ip_offset));
4299 return;
4302 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4303 case 1:
4304 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4305 break;
4306 case 2:
4307 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4308 break;
4311 ctx->target = target;
4314 static void
4315 do_switch (VerifyContext *ctx, int count, const unsigned char *data)
4317 int i, base = ctx->ip_offset + 5 + count * 4;
4318 ILStackDesc *value;
4320 if (!check_underflow (ctx, 1))
4321 return;
4323 value = stack_pop (ctx);
4325 if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
4326 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to switch at 0x%04x", ctx->ip_offset));
4328 for (i = 0; i < count; ++i) {
4329 int target = base + read32 (data + i * 4);
4331 if (target < 0 || target >= ctx->code_size) {
4332 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x out of code at 0x%04x", i, ctx->ip_offset));
4333 return;
4336 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4337 case 1:
4338 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4339 break;
4340 case 2:
4341 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4342 return;
4344 merge_stacks (ctx, &ctx->eval, &ctx->code [target], FALSE, TRUE);
4348 static void
4349 do_load_function_ptr (VerifyContext *ctx, guint32 token, gboolean virtual_)
4351 ILStackDesc *top;
4352 MonoMethod *method;
4354 if (virtual_ && !check_underflow (ctx, 1))
4355 return;
4357 if (!virtual_ && !check_overflow (ctx))
4358 return;
4360 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
4361 method = (MonoMethod *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
4362 if (!method) {
4363 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4364 return;
4366 } else {
4367 if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
4368 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4369 return;
4372 if (!(method = verifier_load_method (ctx, token, virtual_ ? "ldvirtfrn" : "ldftn")))
4373 return;
4376 if (mono_method_is_constructor (method))
4377 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldftn with a constructor at 0x%04x", ctx->ip_offset));
4379 if (virtual_) {
4380 ILStackDesc *top = stack_pop (ctx);
4382 if (stack_slot_get_type (top) != TYPE_COMPLEX || top->type->type == MONO_TYPE_VALUETYPE)
4383 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to ldvirtftn at 0x%04x", ctx->ip_offset));
4385 if (method->flags & METHOD_ATTRIBUTE_STATIC)
4386 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldvirtftn with a constructor at 0x%04x", ctx->ip_offset));
4388 if (!verify_stack_type_compatibility (ctx, &method->klass->byval_arg, top))
4389 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unexpected object for ldvirtftn at 0x%04x", ctx->ip_offset));
4392 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL))
4393 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);
4395 top = stack_push_val(ctx, TYPE_PTR, mono_type_create_fnptr_from_mono_method (ctx, method));
4396 top->method = method;
4399 static void
4400 do_sizeof (VerifyContext *ctx, int token)
4402 MonoType *type;
4404 if (!(type = verifier_load_type (ctx, token, "sizeof")))
4405 return;
4407 if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
4408 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type at 0x%04x", ctx->ip_offset));
4409 return;
4412 if (type->type == MONO_TYPE_VOID) {
4413 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type at 0x%04x", ctx->ip_offset));
4414 return;
4417 if (check_overflow (ctx))
4418 set_stack_value (ctx, stack_push (ctx), &mono_defaults.uint32_class->byval_arg, FALSE);
4421 /* Stack top can be of any type, the runtime doesn't care and treat everything as an int. */
4422 static void
4423 do_localloc (VerifyContext *ctx)
4425 if (ctx->eval.size != 1) {
4426 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4427 return;
4430 if (in_any_exception_block (ctx->header, ctx->ip_offset)) {
4431 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4432 return;
4435 /*TODO verify top type*/
4436 /* top = */ stack_pop (ctx);
4438 set_stack_value (ctx, stack_push (ctx), &mono_defaults.int_class->byval_arg, FALSE);
4439 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Instruction localloc in never verifiable at 0x%04x", ctx->ip_offset));
4442 static void
4443 do_ldstr (VerifyContext *ctx, guint32 token)
4445 GSList *error = NULL;
4446 if (ctx->method->wrapper_type == MONO_WRAPPER_NONE && !image_is_dynamic (ctx->image)) {
4447 if (mono_metadata_token_code (token) != MONO_TOKEN_STRING) {
4448 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string token %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4449 return;
4452 if (!mono_verifier_verify_string_signature (ctx->image, mono_metadata_token_index (token), &error)) {
4453 if (error)
4454 ctx->list = g_slist_concat (ctx->list, error);
4455 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string index %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4456 return;
4460 if (check_overflow (ctx))
4461 stack_push_val (ctx, TYPE_COMPLEX, &mono_defaults.string_class->byval_arg);
4464 static void
4465 do_refanyval (VerifyContext *ctx, int token)
4467 ILStackDesc *top;
4468 MonoType *type;
4469 if (!check_underflow (ctx, 1))
4470 return;
4472 if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4473 return;
4475 top = stack_pop (ctx);
4477 if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4478 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));
4480 set_stack_value (ctx, stack_push (ctx), type, TRUE);
4483 static void
4484 do_refanytype (VerifyContext *ctx)
4486 ILStackDesc *top;
4488 if (!check_underflow (ctx, 1))
4489 return;
4491 top = stack_pop (ctx);
4493 if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4494 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));
4496 set_stack_value (ctx, stack_push (ctx), &mono_defaults.typehandle_class->byval_arg, FALSE);
4500 static void
4501 do_mkrefany (VerifyContext *ctx, int token)
4503 ILStackDesc *top;
4504 MonoType *type;
4505 if (!check_underflow (ctx, 1))
4506 return;
4508 if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4509 return;
4511 top = stack_pop (ctx);
4513 if (stack_slot_is_managed_mutability_pointer (top))
4514 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with mkrefany at 0x%04x", ctx->ip_offset));
4516 if (!stack_slot_is_managed_pointer (top)) {
4517 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));
4518 }else {
4519 MonoType *stack_type = mono_type_get_type_byval (top->type);
4520 if (MONO_TYPE_IS_REFERENCE (type) && !mono_metadata_type_equal (type, stack_type))
4521 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4523 if (!MONO_TYPE_IS_REFERENCE (type) && !verify_type_compatibility_full (ctx, type, stack_type, TRUE))
4524 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4527 set_stack_value (ctx, stack_push (ctx), &mono_defaults.typed_reference_class->byval_arg, FALSE);
4530 static void
4531 do_ckfinite (VerifyContext *ctx)
4533 ILStackDesc *top;
4534 if (!check_underflow (ctx, 1))
4535 return;
4537 top = stack_pop (ctx);
4539 if (stack_slot_get_underlying_type (top) != TYPE_R8)
4540 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));
4541 stack_push_stack_val (ctx, top);
4544 * merge_stacks:
4545 * Merge the stacks and perform compat checks. The merge check if types of @from are mergeable with type of @to
4547 * @from holds new values for a given control path
4548 * @to holds the current values of a given control path
4550 * TODO we can eliminate the from argument as all callers pass &ctx->eval
4552 static void
4553 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external)
4555 MonoError error;
4556 int i, j;
4557 stack_init (ctx, to);
4559 if (start) {
4560 if (to->flags == IL_CODE_FLAG_NOT_PROCESSED)
4561 from->size = 0;
4562 else
4563 stack_copy (&ctx->eval, to);
4564 goto end_verify;
4565 } else if (!(to->flags & IL_CODE_STACK_MERGED)) {
4566 stack_copy (to, &ctx->eval);
4567 goto end_verify;
4569 VERIFIER_DEBUG ( printf ("performing stack merge %d x %d\n", from->size, to->size); );
4571 if (from->size != to->size) {
4572 VERIFIER_DEBUG ( printf ("different stack sizes %d x %d at 0x%04x\n", from->size, to->size, ctx->ip_offset); );
4573 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));
4574 goto end_verify;
4577 //FIXME we need to preserve CMMP attributes
4578 //FIXME we must take null literals into consideration.
4579 for (i = 0; i < from->size; ++i) {
4580 ILStackDesc *new_slot = from->stack + i;
4581 ILStackDesc *old_slot = to->stack + i;
4582 MonoType *new_type = mono_type_from_stack_slot (new_slot);
4583 MonoType *old_type = mono_type_from_stack_slot (old_slot);
4584 MonoClass *old_class = mono_class_from_mono_type (old_type);
4585 MonoClass *new_class = mono_class_from_mono_type (new_type);
4586 MonoClass *match_class = NULL;
4588 // S := T then U = S (new value is compatible with current value, keep current)
4589 if (verify_stack_type_compatibility (ctx, old_type, new_slot)) {
4590 copy_stack_value (new_slot, old_slot);
4591 continue;
4594 // T := S then U = T (old value is compatible with current value, use new)
4595 if (verify_stack_type_compatibility (ctx, new_type, old_slot)) {
4596 copy_stack_value (old_slot, new_slot);
4597 continue;
4600 /*Both slots are the same boxed valuetype. Simply copy it.*/
4601 if (stack_slot_is_boxed_value (old_slot) &&
4602 stack_slot_is_boxed_value (new_slot) &&
4603 mono_metadata_type_equal (old_type, new_type)) {
4604 copy_stack_value (new_slot, old_slot);
4605 continue;
4608 if (mono_type_is_generic_argument (old_type) || mono_type_is_generic_argument (new_type)) {
4609 char *old_name = stack_slot_full_name (old_slot);
4610 char *new_name = stack_slot_full_name (new_slot);
4611 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));
4612 g_free (old_name);
4613 g_free (new_name);
4614 goto end_verify;
4617 //both are reference types, use closest common super type
4618 if (!mono_class_from_mono_type (old_type)->valuetype
4619 && !mono_class_from_mono_type (new_type)->valuetype
4620 && !stack_slot_is_managed_pointer (old_slot)
4621 && !stack_slot_is_managed_pointer (new_slot)) {
4623 mono_class_setup_supertypes (old_class);
4624 mono_class_setup_supertypes (new_class);
4626 for (j = MIN (old_class->idepth, new_class->idepth) - 1; j > 0; --j) {
4627 if (mono_metadata_type_equal (&old_class->supertypes [j]->byval_arg, &new_class->supertypes [j]->byval_arg)) {
4628 match_class = old_class->supertypes [j];
4629 goto match_found;
4633 mono_class_setup_interfaces (old_class, &error);
4634 if (!mono_error_ok (&error)) {
4635 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));
4636 mono_error_cleanup (&error);
4637 goto end_verify;
4639 mono_class_setup_interfaces (new_class, &error);
4640 if (!mono_error_ok (&error)) {
4641 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));
4642 mono_error_cleanup (&error);
4643 goto end_verify;
4646 /* if old class is an interface that new class implements */
4647 if (mono_class_is_interface (old_class)) {
4648 if (verifier_class_is_assignable_from (old_class, new_class)) {
4649 match_class = old_class;
4650 goto match_found;
4652 for (j = 0; j < old_class->interface_count; ++j) {
4653 if (verifier_class_is_assignable_from (old_class->interfaces [j], new_class)) {
4654 match_class = old_class->interfaces [j];
4655 goto match_found;
4660 if (mono_class_is_interface (new_class)) {
4661 if (verifier_class_is_assignable_from (new_class, old_class)) {
4662 match_class = new_class;
4663 goto match_found;
4665 for (j = 0; j < new_class->interface_count; ++j) {
4666 if (verifier_class_is_assignable_from (new_class->interfaces [j], old_class)) {
4667 match_class = new_class->interfaces [j];
4668 goto match_found;
4673 //No decent super type found, use object
4674 match_class = mono_defaults.object_class;
4675 goto match_found;
4676 } 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)) {
4677 match_class = mono_defaults.object_class;
4678 goto match_found;
4682 char *old_name = stack_slot_full_name (old_slot);
4683 char *new_name = stack_slot_full_name (new_slot);
4684 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));
4685 g_free (old_name);
4686 g_free (new_name);
4688 set_stack_value (ctx, old_slot, &new_class->byval_arg, stack_slot_is_managed_pointer (old_slot));
4689 goto end_verify;
4691 match_found:
4692 g_assert (match_class);
4693 set_stack_value (ctx, old_slot, &match_class->byval_arg, stack_slot_is_managed_pointer (old_slot));
4694 set_stack_value (ctx, new_slot, &match_class->byval_arg, stack_slot_is_managed_pointer (old_slot));
4695 continue;
4698 end_verify:
4699 if (external)
4700 to->flags |= IL_CODE_FLAG_WAS_TARGET;
4701 to->flags |= IL_CODE_STACK_MERGED;
4704 #define HANDLER_START(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER ? (clause)->data.filter_offset : clause->handler_offset)
4705 #define IS_CATCH_OR_FILTER(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER || (clause)->flags == MONO_EXCEPTION_CLAUSE_NONE)
4708 * is_clause_in_range :
4710 * Returns TRUE if either the protected block or the handler of @clause is in the @start - @end range.
4712 static gboolean
4713 is_clause_in_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4715 if (clause->try_offset >= start && clause->try_offset < end)
4716 return TRUE;
4717 if (HANDLER_START (clause) >= start && HANDLER_START (clause) < end)
4718 return TRUE;
4719 return FALSE;
4723 * is_clause_inside_range :
4725 * Returns TRUE if @clause lies completely inside the @start - @end range.
4727 static gboolean
4728 is_clause_inside_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4730 if (clause->try_offset < start || (clause->try_offset + clause->try_len) > end)
4731 return FALSE;
4732 if (HANDLER_START (clause) < start || (clause->handler_offset + clause->handler_len) > end)
4733 return FALSE;
4734 return TRUE;
4738 * is_clause_nested :
4740 * Returns TRUE if @nested is nested in @clause.
4742 static gboolean
4743 is_clause_nested (MonoExceptionClause *clause, MonoExceptionClause *nested)
4745 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (nested, clause->data.filter_offset, clause->handler_offset))
4746 return TRUE;
4747 return is_clause_inside_range (nested, clause->try_offset, clause->try_offset + clause->try_len) ||
4748 is_clause_inside_range (nested, clause->handler_offset, clause->handler_offset + clause->handler_len);
4751 /* Test the relationship between 2 exception clauses. Follow P.1 12.4.2.7 of ECMA
4752 * the each pair of exception must have the following properties:
4753 * - one is fully nested on another (the outer must not be a filter clause) (the nested one must come earlier)
4754 * - completely disjoin (none of the 3 regions of each entry overlap with the other 3)
4755 * - mutual protection (protected block is EXACT the same, handlers are disjoin and all handler are catch or all handler are filter)
4757 static void
4758 verify_clause_relationship (VerifyContext *ctx, MonoExceptionClause *clause, MonoExceptionClause *to_test)
4760 /*clause is nested*/
4761 if (to_test->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (clause, to_test->data.filter_offset, to_test->handler_offset)) {
4762 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clause inside filter"));
4763 return;
4766 /*wrong nesting order.*/
4767 if (is_clause_nested (clause, to_test)) {
4768 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Nested exception clause appears after enclosing clause"));
4769 return;
4772 /*mutual protection*/
4773 if (clause->try_offset == to_test->try_offset && clause->try_len == to_test->try_len) {
4774 /*handlers are not disjoint*/
4775 if (is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) {
4776 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception handlers overlap"));
4777 return;
4779 /* handlers are not catch or filter */
4780 if (!IS_CATCH_OR_FILTER (clause) || !IS_CATCH_OR_FILTER (to_test)) {
4781 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses with shared protected block are neither catch or filter"));
4782 return;
4784 /*OK*/
4785 return;
4788 /*not completelly disjoint*/
4789 if ((is_clause_in_range (to_test, clause->try_offset, clause->try_offset + clause->try_len) ||
4790 is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) && !is_clause_nested (to_test, clause))
4791 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses overlap"));
4794 #define code_bounds_check(size) \
4795 if (ADDP_IS_GREATER_OR_OVF (ip, size, end)) {\
4796 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Code overrun starting with 0x%x at 0x%04x", *ip, ctx.ip_offset)); \
4797 break; \
4800 static gboolean
4801 mono_opcode_is_prefix (int op)
4803 switch (op) {
4804 case MONO_CEE_UNALIGNED_:
4805 case MONO_CEE_VOLATILE_:
4806 case MONO_CEE_TAIL_:
4807 case MONO_CEE_CONSTRAINED_:
4808 case MONO_CEE_READONLY_:
4809 return TRUE;
4811 return FALSE;
4815 * FIXME: need to distinguish between valid and verifiable.
4816 * Need to keep track of types on the stack.
4817 * Verify types for opcodes.
4819 GSList*
4820 mono_method_verify (MonoMethod *method, int level)
4822 MonoError error;
4823 const unsigned char *ip, *code_start;
4824 const unsigned char *end;
4825 MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
4827 int i, n, need_merge = 0, start = 0;
4828 guint ip_offset = 0, prefix = 0;
4829 MonoGenericContext *generic_context = NULL;
4830 MonoImage *image;
4831 VerifyContext ctx;
4832 GSList *tmp;
4833 VERIFIER_DEBUG ( printf ("Verify IL for method %s %s %s\n", method->klass->name_space, method->klass->name, method->name); );
4835 init_verifier_stats ();
4837 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
4838 (method->flags & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT))) {
4839 return NULL;
4842 memset (&ctx, 0, sizeof (VerifyContext));
4844 //FIXME use mono_method_get_signature_full
4845 ctx.signature = mono_method_signature (method);
4846 if (!ctx.signature) {
4847 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method signature"));
4849 finish_collect_stats ();
4850 return ctx.list;
4852 if (!method->is_generic && !mono_class_is_gtd (method->klass) && ctx.signature->has_type_parameters) {
4853 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Method and signature don't match in terms of genericity"));
4854 finish_collect_stats ();
4855 return ctx.list;
4858 ctx.header = mono_method_get_header_checked (method, &error);
4859 if (!ctx.header) {
4860 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method header due to %s", mono_error_get_message (&error)));
4861 mono_error_cleanup (&error);
4862 finish_collect_stats ();
4863 return ctx.list;
4865 ctx.method = method;
4866 code_start = ip = ctx.header->code;
4867 end = ip + ctx.header->code_size;
4868 ctx.image = image = method->klass->image;
4871 ctx.max_args = ctx.signature->param_count + ctx.signature->hasthis;
4872 ctx.max_stack = ctx.header->max_stack;
4873 ctx.verifiable = ctx.valid = 1;
4874 ctx.level = level;
4876 ctx.code = g_new (ILCodeDesc, ctx.header->code_size);
4877 ctx.code_size = ctx.header->code_size;
4878 _MEM_ALLOC (sizeof (ILCodeDesc) * ctx.header->code_size);
4880 memset(ctx.code, 0, sizeof (ILCodeDesc) * ctx.header->code_size);
4882 ctx.num_locals = ctx.header->num_locals;
4883 ctx.locals = (MonoType **)g_memdup (ctx.header->locals, sizeof (MonoType*) * ctx.header->num_locals);
4884 _MEM_ALLOC (sizeof (MonoType*) * ctx.header->num_locals);
4886 if (ctx.num_locals > 0 && !ctx.header->init_locals)
4887 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Method with locals variable but without init locals set"));
4889 ctx.params = g_new (MonoType*, ctx.max_args);
4890 _MEM_ALLOC (sizeof (MonoType*) * ctx.max_args);
4892 if (ctx.signature->hasthis)
4893 ctx.params [0] = method->klass->valuetype ? &method->klass->this_arg : &method->klass->byval_arg;
4894 memcpy (ctx.params + ctx.signature->hasthis, ctx.signature->params, sizeof (MonoType *) * ctx.signature->param_count);
4896 if (ctx.signature->is_inflated)
4897 ctx.generic_context = generic_context = mono_method_get_context (method);
4899 if (!generic_context && (mono_class_is_gtd (method->klass) || method->is_generic)) {
4900 if (method->is_generic)
4901 ctx.generic_context = generic_context = &(mono_method_get_generic_container (method)->context);
4902 else
4903 ctx.generic_context = generic_context = &mono_class_get_generic_container (method->klass)->context;
4906 for (i = 0; i < ctx.num_locals; ++i) {
4907 MonoType *uninflated = ctx.locals [i];
4908 ctx.locals [i] = mono_class_inflate_generic_type_checked (ctx.locals [i], ctx.generic_context, &error);
4909 if (!mono_error_ok (&error)) {
4910 char *name = mono_type_full_name (ctx.locals [i] ? ctx.locals [i] : uninflated);
4911 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %d of type %s", i, name));
4912 g_free (name);
4913 mono_error_cleanup (&error);
4914 /* we must not free (in cleanup) what was not yet allocated (but only copied) */
4915 ctx.num_locals = i;
4916 ctx.max_args = 0;
4917 goto cleanup;
4920 for (i = 0; i < ctx.max_args; ++i) {
4921 MonoType *uninflated = ctx.params [i];
4922 ctx.params [i] = mono_class_inflate_generic_type_checked (ctx.params [i], ctx.generic_context, &error);
4923 if (!mono_error_ok (&error)) {
4924 char *name = mono_type_full_name (ctx.params [i] ? ctx.params [i] : uninflated);
4925 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %d of type %s", i, name));
4926 g_free (name);
4927 mono_error_cleanup (&error);
4928 /* we must not free (in cleanup) what was not yet allocated (but only copied) */
4929 ctx.max_args = i;
4930 goto cleanup;
4933 stack_init (&ctx, &ctx.eval);
4935 for (i = 0; i < ctx.num_locals; ++i) {
4936 if (!mono_type_is_valid_in_context (&ctx, ctx.locals [i]))
4937 break;
4938 if (get_stack_type (ctx.locals [i]) == TYPE_INV) {
4939 char *name = mono_type_full_name (ctx.locals [i]);
4940 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %i of type %s", i, name));
4941 g_free (name);
4942 break;
4947 for (i = 0; i < ctx.max_args; ++i) {
4948 if (!mono_type_is_valid_in_context (&ctx, ctx.params [i]))
4949 break;
4951 if (get_stack_type (ctx.params [i]) == TYPE_INV) {
4952 char *name = mono_type_full_name (ctx.params [i]);
4953 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %i of type %s", i, name));
4954 g_free (name);
4955 break;
4959 if (!ctx.valid)
4960 goto cleanup;
4962 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
4963 MonoExceptionClause *clause = ctx.header->clauses + i;
4964 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); );
4966 if (clause->try_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, ctx.code_size))
4967 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause out of bounds at 0x%04x", clause->try_offset));
4969 if (clause->try_len <= 0)
4970 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause len <= 0 at 0x%04x", clause->try_offset));
4972 if (clause->handler_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->handler_offset, clause->handler_len, ctx.code_size))
4973 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause out of bounds at 0x%04x", clause->try_offset));
4975 if (clause->handler_len <= 0)
4976 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause len <= 0 at 0x%04x", clause->try_offset));
4978 if (clause->try_offset < clause->handler_offset && ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, HANDLER_START (clause)))
4979 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try block (at 0x%04x) includes handler block (at 0x%04x)", clause->try_offset, clause->handler_offset));
4981 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4982 if (clause->data.filter_offset > ctx.code_size)
4983 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause out of bounds at 0x%04x", clause->try_offset));
4985 if (clause->data.filter_offset >= clause->handler_offset)
4986 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause must come before the handler clause at 0x%04x", clause->data.filter_offset));
4989 for (n = i + 1; n < ctx.header->num_clauses && ctx.valid; ++n)
4990 verify_clause_relationship (&ctx, clause, ctx.header->clauses + n);
4992 if (!ctx.valid)
4993 break;
4995 ctx.code [clause->try_offset].flags |= IL_CODE_FLAG_WAS_TARGET;
4996 if (clause->try_offset + clause->try_len < ctx.code_size)
4997 ctx.code [clause->try_offset + clause->try_len].flags |= IL_CODE_FLAG_WAS_TARGET;
4998 if (clause->handler_offset + clause->handler_len < ctx.code_size)
4999 ctx.code [clause->handler_offset + clause->handler_len].flags |= IL_CODE_FLAG_WAS_TARGET;
5001 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
5002 if (!clause->data.catch_class) {
5003 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Catch clause %d with invalid type", i));
5004 break;
5006 if (!mono_type_is_valid_in_context (&ctx, &clause->data.catch_class->byval_arg))
5007 break;
5009 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, clause->data.catch_class);
5011 else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5012 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->data.filter_offset, mono_defaults.exception_class);
5013 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, mono_defaults.exception_class);
5017 if (!ctx.valid)
5018 goto cleanup;
5020 original_bb = bb = mono_basic_block_split (method, &error, ctx.header);
5021 if (!mono_error_ok (&error)) {
5022 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid branch target: %s", mono_error_get_message (&error)));
5023 mono_error_cleanup (&error);
5024 goto cleanup;
5026 g_assert (bb);
5028 while (ip < end && ctx.valid) {
5029 int op_size;
5030 ip_offset = (guint) (ip - code_start);
5032 const unsigned char *ip_copy = ip;
5033 int op;
5035 if (ip_offset > bb->end) {
5036 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block at [0x%04x] targets middle instruction at 0x%04x", bb->end, ip_offset));
5037 goto cleanup;
5040 if (ip_offset == bb->end)
5041 bb = bb->next;
5043 op_size = mono_opcode_value_and_size (&ip_copy, end, &op);
5044 if (op_size == -1) {
5045 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ip_offset));
5046 goto cleanup;
5049 if (ADD_IS_GREATER_OR_OVF (ip_offset, op_size, bb->end)) {
5050 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block targets middle of instruction at 0x%04x", ip_offset));
5051 goto cleanup;
5054 /*Last Instruction*/
5055 if (ip_offset + op_size == bb->end && mono_opcode_is_prefix (op)) {
5056 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));
5057 goto cleanup;
5061 ctx.ip_offset = ip_offset = (guint) (ip - code_start);
5063 /*We need to check against fallthrou in and out of protected blocks.
5064 * For fallout we check the once a protected block ends, if the start flag is not set.
5065 * Likewise for fallthru in, we check if ip is the start of a protected block and start is not set
5066 * TODO convert these checks to be done using flags and not this loop
5068 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
5069 MonoExceptionClause *clause = ctx.header->clauses + i;
5071 if ((clause->try_offset + clause->try_len == ip_offset) && start == 0) {
5072 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru off try block at 0x%04x", ip_offset));
5073 start = 1;
5076 if ((clause->handler_offset + clause->handler_len == ip_offset) && start == 0) {
5077 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
5078 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
5079 else
5080 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
5081 start = 1;
5084 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && clause->handler_offset == ip_offset && start == 0) {
5085 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of filter block at 0x%04x", ip_offset));
5086 start = 1;
5089 if (clause->handler_offset == ip_offset && start == 0) {
5090 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru handler block at 0x%04x", ip_offset));
5091 start = 1;
5094 if (clause->try_offset == ip_offset && ctx.eval.size > 0 && start == 0) {
5095 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Try to enter try block with a non-empty stack at 0x%04x", ip_offset));
5096 start = 1;
5100 /*This must be done after fallthru detection otherwise it won't happen.*/
5101 if (bb->dead) {
5102 /*FIXME remove this once we move all bad branch checking code to use BB only*/
5103 ctx.code [ip_offset].flags |= IL_CODE_FLAG_SEEN;
5104 ip += op_size;
5105 continue;
5108 if (!ctx.valid)
5109 break;
5111 if (need_merge) {
5112 VERIFIER_DEBUG ( printf ("extra merge needed! 0x%04x \n", ctx.target); );
5113 merge_stacks (&ctx, &ctx.eval, &ctx.code [ctx.target], FALSE, TRUE);
5114 need_merge = 0;
5116 merge_stacks (&ctx, &ctx.eval, &ctx.code[ip_offset], start, FALSE);
5117 start = 0;
5119 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
5120 #ifdef MONO_VERIFIER_DEBUG
5122 char *discode;
5123 discode = mono_disasm_code_one (NULL, method, ip, NULL);
5124 discode [strlen (discode) - 1] = 0; /* no \n */
5125 g_print ("[%d] %-29s (%d)\n", ip_offset, discode, ctx.eval.size);
5126 g_free (discode);
5128 dump_stack_state (&ctx.code [ip_offset]);
5129 dump_stack_state (&ctx.eval);
5130 #endif
5132 switch (*ip) {
5133 case CEE_NOP:
5134 case CEE_BREAK:
5135 ++ip;
5136 break;
5138 case CEE_LDARG_0:
5139 case CEE_LDARG_1:
5140 case CEE_LDARG_2:
5141 case CEE_LDARG_3:
5142 push_arg (&ctx, *ip - CEE_LDARG_0, FALSE);
5143 ++ip;
5144 break;
5146 case CEE_LDARG_S:
5147 case CEE_LDARGA_S:
5148 code_bounds_check (2);
5149 push_arg (&ctx, ip [1], *ip == CEE_LDARGA_S);
5150 ip += 2;
5151 break;
5153 case CEE_ADD_OVF_UN:
5154 do_binop (&ctx, *ip, add_ovf_un_table);
5155 ++ip;
5156 break;
5158 case CEE_SUB_OVF_UN:
5159 do_binop (&ctx, *ip, sub_ovf_un_table);
5160 ++ip;
5161 break;
5163 case CEE_ADD_OVF:
5164 case CEE_SUB_OVF:
5165 case CEE_MUL_OVF:
5166 case CEE_MUL_OVF_UN:
5167 do_binop (&ctx, *ip, bin_ovf_table);
5168 ++ip;
5169 break;
5171 case CEE_ADD:
5172 do_binop (&ctx, *ip, add_table);
5173 ++ip;
5174 break;
5176 case CEE_SUB:
5177 do_binop (&ctx, *ip, sub_table);
5178 ++ip;
5179 break;
5181 case CEE_MUL:
5182 case CEE_DIV:
5183 case CEE_REM:
5184 do_binop (&ctx, *ip, bin_op_table);
5185 ++ip;
5186 break;
5188 case CEE_AND:
5189 case CEE_DIV_UN:
5190 case CEE_OR:
5191 case CEE_REM_UN:
5192 case CEE_XOR:
5193 do_binop (&ctx, *ip, int_bin_op_table);
5194 ++ip;
5195 break;
5197 case CEE_SHL:
5198 case CEE_SHR:
5199 case CEE_SHR_UN:
5200 do_binop (&ctx, *ip, shift_op_table);
5201 ++ip;
5202 break;
5204 case CEE_POP:
5205 if (!check_underflow (&ctx, 1))
5206 break;
5207 stack_pop_safe (&ctx);
5208 ++ip;
5209 break;
5211 case CEE_RET:
5212 do_ret (&ctx);
5213 ++ip;
5214 start = 1;
5215 break;
5217 case CEE_LDLOC_0:
5218 case CEE_LDLOC_1:
5219 case CEE_LDLOC_2:
5220 case CEE_LDLOC_3:
5221 /*TODO support definite assignment verification? */
5222 push_local (&ctx, *ip - CEE_LDLOC_0, FALSE);
5223 ++ip;
5224 break;
5226 case CEE_STLOC_0:
5227 case CEE_STLOC_1:
5228 case CEE_STLOC_2:
5229 case CEE_STLOC_3:
5230 store_local (&ctx, *ip - CEE_STLOC_0);
5231 ++ip;
5232 break;
5234 case CEE_STLOC_S:
5235 code_bounds_check (2);
5236 store_local (&ctx, ip [1]);
5237 ip += 2;
5238 break;
5240 case CEE_STARG_S:
5241 code_bounds_check (2);
5242 store_arg (&ctx, ip [1]);
5243 ip += 2;
5244 break;
5246 case CEE_LDC_I4_M1:
5247 case CEE_LDC_I4_0:
5248 case CEE_LDC_I4_1:
5249 case CEE_LDC_I4_2:
5250 case CEE_LDC_I4_3:
5251 case CEE_LDC_I4_4:
5252 case CEE_LDC_I4_5:
5253 case CEE_LDC_I4_6:
5254 case CEE_LDC_I4_7:
5255 case CEE_LDC_I4_8:
5256 if (check_overflow (&ctx))
5257 stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
5258 ++ip;
5259 break;
5261 case CEE_LDC_I4_S:
5262 code_bounds_check (2);
5263 if (check_overflow (&ctx))
5264 stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
5265 ip += 2;
5266 break;
5268 case CEE_LDC_I4:
5269 code_bounds_check (5);
5270 if (check_overflow (&ctx))
5271 stack_push_val (&ctx,TYPE_I4, &mono_defaults.int32_class->byval_arg);
5272 ip += 5;
5273 break;
5275 case CEE_LDC_I8:
5276 code_bounds_check (9);
5277 if (check_overflow (&ctx))
5278 stack_push_val (&ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
5279 ip += 9;
5280 break;
5282 case CEE_LDC_R4:
5283 code_bounds_check (5);
5284 if (check_overflow (&ctx))
5285 stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
5286 ip += 5;
5287 break;
5289 case CEE_LDC_R8:
5290 code_bounds_check (9);
5291 if (check_overflow (&ctx))
5292 stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
5293 ip += 9;
5294 break;
5296 case CEE_LDNULL:
5297 if (check_overflow (&ctx))
5298 stack_push_val (&ctx, TYPE_COMPLEX | NULL_LITERAL_MASK, &mono_defaults.object_class->byval_arg);
5299 ++ip;
5300 break;
5302 case CEE_BEQ_S:
5303 case CEE_BNE_UN_S:
5304 code_bounds_check (2);
5305 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_eq_op);
5306 ip += 2;
5307 need_merge = 1;
5308 break;
5310 case CEE_BGE_S:
5311 case CEE_BGT_S:
5312 case CEE_BLE_S:
5313 case CEE_BLT_S:
5314 case CEE_BGE_UN_S:
5315 case CEE_BGT_UN_S:
5316 case CEE_BLE_UN_S:
5317 case CEE_BLT_UN_S:
5318 code_bounds_check (2);
5319 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_op);
5320 ip += 2;
5321 need_merge = 1;
5322 break;
5324 case CEE_BEQ:
5325 case CEE_BNE_UN:
5326 code_bounds_check (5);
5327 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_eq_op);
5328 ip += 5;
5329 need_merge = 1;
5330 break;
5332 case CEE_BGE:
5333 case CEE_BGT:
5334 case CEE_BLE:
5335 case CEE_BLT:
5336 case CEE_BGE_UN:
5337 case CEE_BGT_UN:
5338 case CEE_BLE_UN:
5339 case CEE_BLT_UN:
5340 code_bounds_check (5);
5341 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_op);
5342 ip += 5;
5343 need_merge = 1;
5344 break;
5346 case CEE_LDLOC_S:
5347 case CEE_LDLOCA_S:
5348 code_bounds_check (2);
5349 push_local (&ctx, ip[1], *ip == CEE_LDLOCA_S);
5350 ip += 2;
5351 break;
5353 case CEE_UNUSED99:
5354 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5355 ++ip;
5356 break;
5358 case CEE_DUP: {
5359 ILStackDesc *top;
5360 if (!check_underflow (&ctx, 1))
5361 break;
5362 if (!check_overflow (&ctx))
5363 break;
5364 top = stack_push (&ctx);
5365 copy_stack_value (top, stack_peek (&ctx, 1));
5366 ++ip;
5367 break;
5370 case CEE_JMP:
5371 code_bounds_check (5);
5372 if (ctx.eval.size)
5373 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Eval stack must be empty in jmp at 0x%04x", ip_offset));
5374 /* token = read32 (ip + 1); */
5375 if (in_any_block (ctx.header, ip_offset))
5376 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("jmp cannot escape exception blocks at 0x%04x", ip_offset));
5378 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction jmp is not verifiable at 0x%04x", ctx.ip_offset));
5380 * FIXME: check signature, retval, arguments etc.
5382 ip += 5;
5383 break;
5384 case CEE_CALL:
5385 case CEE_CALLVIRT:
5386 code_bounds_check (5);
5387 do_invoke_method (&ctx, read32 (ip + 1), *ip == CEE_CALLVIRT);
5388 ip += 5;
5389 break;
5391 case CEE_CALLI:
5392 code_bounds_check (5);
5393 /* token = read32 (ip + 1); */
5395 * FIXME: check signature, retval, arguments etc.
5396 * FIXME: check requirements for tail call
5398 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction calli is not verifiable at 0x%04x", ctx.ip_offset));
5399 ip += 5;
5400 break;
5401 case CEE_BR_S:
5402 code_bounds_check (2);
5403 do_static_branch (&ctx, (signed char)ip [1] + 2);
5404 need_merge = 1;
5405 ip += 2;
5406 start = 1;
5407 break;
5409 case CEE_BRFALSE_S:
5410 case CEE_BRTRUE_S:
5411 code_bounds_check (2);
5412 do_boolean_branch_op (&ctx, (signed char)ip [1] + 2);
5413 ip += 2;
5414 need_merge = 1;
5415 break;
5417 case CEE_BR:
5418 code_bounds_check (5);
5419 do_static_branch (&ctx, (gint32)read32 (ip + 1) + 5);
5420 need_merge = 1;
5421 ip += 5;
5422 start = 1;
5423 break;
5425 case CEE_BRFALSE:
5426 case CEE_BRTRUE:
5427 code_bounds_check (5);
5428 do_boolean_branch_op (&ctx, (gint32)read32 (ip + 1) + 5);
5429 ip += 5;
5430 need_merge = 1;
5431 break;
5433 case CEE_SWITCH: {
5434 guint32 entries;
5435 code_bounds_check (5);
5436 entries = read32 (ip + 1);
5438 if (entries > 0xFFFFFFFFU / sizeof (guint32))
5439 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Too many switch entries %x at 0x%04x", entries, ctx.ip_offset));
5441 ip += 5;
5442 code_bounds_check (sizeof (guint32) * entries);
5444 do_switch (&ctx, entries, ip);
5445 ip += sizeof (guint32) * entries;
5446 break;
5448 case CEE_LDIND_I1:
5449 case CEE_LDIND_U1:
5450 case CEE_LDIND_I2:
5451 case CEE_LDIND_U2:
5452 case CEE_LDIND_I4:
5453 case CEE_LDIND_U4:
5454 case CEE_LDIND_I8:
5455 case CEE_LDIND_I:
5456 case CEE_LDIND_R4:
5457 case CEE_LDIND_R8:
5458 case CEE_LDIND_REF:
5459 do_load_indirect (&ctx, *ip);
5460 ++ip;
5461 break;
5463 case CEE_STIND_REF:
5464 case CEE_STIND_I1:
5465 case CEE_STIND_I2:
5466 case CEE_STIND_I4:
5467 case CEE_STIND_I8:
5468 case CEE_STIND_R4:
5469 case CEE_STIND_R8:
5470 case CEE_STIND_I:
5471 do_store_indirect (&ctx, *ip);
5472 ++ip;
5473 break;
5475 case CEE_NOT:
5476 case CEE_NEG:
5477 do_unary_math_op (&ctx, *ip);
5478 ++ip;
5479 break;
5481 case CEE_CONV_I1:
5482 case CEE_CONV_I2:
5483 case CEE_CONV_I4:
5484 case CEE_CONV_U1:
5485 case CEE_CONV_U2:
5486 case CEE_CONV_U4:
5487 do_conversion (&ctx, TYPE_I4);
5488 ++ip;
5489 break;
5491 case CEE_CONV_I8:
5492 case CEE_CONV_U8:
5493 do_conversion (&ctx, TYPE_I8);
5494 ++ip;
5495 break;
5497 case CEE_CONV_R4:
5498 case CEE_CONV_R8:
5499 case CEE_CONV_R_UN:
5500 do_conversion (&ctx, TYPE_R8);
5501 ++ip;
5502 break;
5504 case CEE_CONV_I:
5505 case CEE_CONV_U:
5506 do_conversion (&ctx, TYPE_NATIVE_INT);
5507 ++ip;
5508 break;
5510 case CEE_CPOBJ:
5511 code_bounds_check (5);
5512 do_cpobj (&ctx, read32 (ip + 1));
5513 ip += 5;
5514 break;
5516 case CEE_LDOBJ:
5517 code_bounds_check (5);
5518 do_ldobj_value (&ctx, read32 (ip + 1));
5519 ip += 5;
5520 break;
5522 case CEE_LDSTR:
5523 code_bounds_check (5);
5524 do_ldstr (&ctx, read32 (ip + 1));
5525 ip += 5;
5526 break;
5528 case CEE_NEWOBJ:
5529 code_bounds_check (5);
5530 do_newobj (&ctx, read32 (ip + 1));
5531 ip += 5;
5532 break;
5534 case CEE_CASTCLASS:
5535 case CEE_ISINST:
5536 code_bounds_check (5);
5537 do_cast (&ctx, read32 (ip + 1), *ip == CEE_CASTCLASS ? "castclass" : "isinst");
5538 ip += 5;
5539 break;
5541 case CEE_UNUSED58:
5542 case CEE_UNUSED1:
5543 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5544 ++ip;
5545 break;
5547 case CEE_UNBOX:
5548 code_bounds_check (5);
5549 do_unbox_value (&ctx, read32 (ip + 1));
5550 ip += 5;
5551 break;
5553 case CEE_THROW:
5554 do_throw (&ctx);
5555 start = 1;
5556 ++ip;
5557 break;
5559 case CEE_LDFLD:
5560 case CEE_LDFLDA:
5561 code_bounds_check (5);
5562 do_push_field (&ctx, read32 (ip + 1), *ip == CEE_LDFLDA);
5563 ip += 5;
5564 break;
5566 case CEE_LDSFLD:
5567 case CEE_LDSFLDA:
5568 code_bounds_check (5);
5569 do_push_static_field (&ctx, read32 (ip + 1), *ip == CEE_LDSFLDA);
5570 ip += 5;
5571 break;
5573 case CEE_STFLD:
5574 code_bounds_check (5);
5575 do_store_field (&ctx, read32 (ip + 1));
5576 ip += 5;
5577 break;
5579 case CEE_STSFLD:
5580 code_bounds_check (5);
5581 do_store_static_field (&ctx, read32 (ip + 1));
5582 ip += 5;
5583 break;
5585 case CEE_STOBJ:
5586 code_bounds_check (5);
5587 do_stobj (&ctx, read32 (ip + 1));
5588 ip += 5;
5589 break;
5591 case CEE_CONV_OVF_I1_UN:
5592 case CEE_CONV_OVF_I2_UN:
5593 case CEE_CONV_OVF_I4_UN:
5594 case CEE_CONV_OVF_U1_UN:
5595 case CEE_CONV_OVF_U2_UN:
5596 case CEE_CONV_OVF_U4_UN:
5597 do_conversion (&ctx, TYPE_I4);
5598 ++ip;
5599 break;
5601 case CEE_CONV_OVF_I8_UN:
5602 case CEE_CONV_OVF_U8_UN:
5603 do_conversion (&ctx, TYPE_I8);
5604 ++ip;
5605 break;
5607 case CEE_CONV_OVF_I_UN:
5608 case CEE_CONV_OVF_U_UN:
5609 do_conversion (&ctx, TYPE_NATIVE_INT);
5610 ++ip;
5611 break;
5613 case CEE_BOX:
5614 code_bounds_check (5);
5615 do_box_value (&ctx, read32 (ip + 1));
5616 ip += 5;
5617 break;
5619 case CEE_NEWARR:
5620 code_bounds_check (5);
5621 do_newarr (&ctx, read32 (ip + 1));
5622 ip += 5;
5623 break;
5625 case CEE_LDLEN:
5626 do_ldlen (&ctx);
5627 ++ip;
5628 break;
5630 case CEE_LDELEMA:
5631 code_bounds_check (5);
5632 do_ldelema (&ctx, read32 (ip + 1));
5633 ip += 5;
5634 break;
5636 case CEE_LDELEM_I1:
5637 case CEE_LDELEM_U1:
5638 case CEE_LDELEM_I2:
5639 case CEE_LDELEM_U2:
5640 case CEE_LDELEM_I4:
5641 case CEE_LDELEM_U4:
5642 case CEE_LDELEM_I8:
5643 case CEE_LDELEM_I:
5644 case CEE_LDELEM_R4:
5645 case CEE_LDELEM_R8:
5646 case CEE_LDELEM_REF:
5647 do_ldelem (&ctx, *ip, 0);
5648 ++ip;
5649 break;
5651 case CEE_STELEM_I:
5652 case CEE_STELEM_I1:
5653 case CEE_STELEM_I2:
5654 case CEE_STELEM_I4:
5655 case CEE_STELEM_I8:
5656 case CEE_STELEM_R4:
5657 case CEE_STELEM_R8:
5658 case CEE_STELEM_REF:
5659 do_stelem (&ctx, *ip, 0);
5660 ++ip;
5661 break;
5663 case CEE_LDELEM:
5664 code_bounds_check (5);
5665 do_ldelem (&ctx, *ip, read32 (ip + 1));
5666 ip += 5;
5667 break;
5669 case CEE_STELEM:
5670 code_bounds_check (5);
5671 do_stelem (&ctx, *ip, read32 (ip + 1));
5672 ip += 5;
5673 break;
5675 case CEE_UNBOX_ANY:
5676 code_bounds_check (5);
5677 do_unbox_any (&ctx, read32 (ip + 1));
5678 ip += 5;
5679 break;
5681 case CEE_CONV_OVF_I1:
5682 case CEE_CONV_OVF_U1:
5683 case CEE_CONV_OVF_I2:
5684 case CEE_CONV_OVF_U2:
5685 case CEE_CONV_OVF_I4:
5686 case CEE_CONV_OVF_U4:
5687 do_conversion (&ctx, TYPE_I4);
5688 ++ip;
5689 break;
5691 case CEE_CONV_OVF_I8:
5692 case CEE_CONV_OVF_U8:
5693 do_conversion (&ctx, TYPE_I8);
5694 ++ip;
5695 break;
5697 case CEE_CONV_OVF_I:
5698 case CEE_CONV_OVF_U:
5699 do_conversion (&ctx, TYPE_NATIVE_INT);
5700 ++ip;
5701 break;
5703 case CEE_REFANYVAL:
5704 code_bounds_check (5);
5705 do_refanyval (&ctx, read32 (ip + 1));
5706 ip += 5;
5707 break;
5709 case CEE_CKFINITE:
5710 do_ckfinite (&ctx);
5711 ++ip;
5712 break;
5714 case CEE_MKREFANY:
5715 code_bounds_check (5);
5716 do_mkrefany (&ctx, read32 (ip + 1));
5717 ip += 5;
5718 break;
5720 case CEE_LDTOKEN:
5721 code_bounds_check (5);
5722 do_load_token (&ctx, read32 (ip + 1));
5723 ip += 5;
5724 break;
5726 case CEE_ENDFINALLY:
5727 if (!is_correct_endfinally (ctx.header, ip_offset))
5728 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("endfinally must be used inside a finally/fault handler at 0x%04x", ctx.ip_offset));
5729 ctx.eval.size = 0;
5730 start = 1;
5731 ++ip;
5732 break;
5734 case CEE_LEAVE:
5735 code_bounds_check (5);
5736 do_leave (&ctx, read32 (ip + 1) + 5);
5737 ip += 5;
5738 start = 1;
5739 need_merge = 1;
5740 break;
5742 case CEE_LEAVE_S:
5743 code_bounds_check (2);
5744 do_leave (&ctx, (signed char)ip [1] + 2);
5745 ip += 2;
5746 start = 1;
5747 need_merge = 1;
5748 break;
5750 case CEE_PREFIX1:
5751 code_bounds_check (2);
5752 ++ip;
5753 switch (*ip) {
5754 case CEE_STLOC:
5755 code_bounds_check (3);
5756 store_local (&ctx, read16 (ip + 1));
5757 ip += 3;
5758 break;
5760 case CEE_CEQ:
5761 do_cmp_op (&ctx, cmp_br_eq_op, *ip);
5762 ++ip;
5763 break;
5765 case CEE_CGT:
5766 case CEE_CGT_UN:
5767 case CEE_CLT:
5768 case CEE_CLT_UN:
5769 do_cmp_op (&ctx, cmp_br_op, *ip);
5770 ++ip;
5771 break;
5773 case CEE_STARG:
5774 code_bounds_check (3);
5775 store_arg (&ctx, read16 (ip + 1) );
5776 ip += 3;
5777 break;
5780 case CEE_ARGLIST:
5781 if (!check_overflow (&ctx))
5782 break;
5783 if (ctx.signature->call_convention != MONO_CALL_VARARG)
5784 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot use arglist on method without VARGARG calling convention at 0x%04x", ctx.ip_offset));
5785 set_stack_value (&ctx, stack_push (&ctx), &mono_defaults.argumenthandle_class->byval_arg, FALSE);
5786 ++ip;
5787 break;
5789 case CEE_LDFTN:
5790 code_bounds_check (5);
5791 do_load_function_ptr (&ctx, read32 (ip + 1), FALSE);
5792 ip += 5;
5793 break;
5795 case CEE_LDVIRTFTN:
5796 code_bounds_check (5);
5797 do_load_function_ptr (&ctx, read32 (ip + 1), TRUE);
5798 ip += 5;
5799 break;
5801 case CEE_LDARG:
5802 case CEE_LDARGA:
5803 code_bounds_check (3);
5804 push_arg (&ctx, read16 (ip + 1), *ip == CEE_LDARGA);
5805 ip += 3;
5806 break;
5808 case CEE_LDLOC:
5809 case CEE_LDLOCA:
5810 code_bounds_check (3);
5811 push_local (&ctx, read16 (ip + 1), *ip == CEE_LDLOCA);
5812 ip += 3;
5813 break;
5815 case CEE_LOCALLOC:
5816 do_localloc (&ctx);
5817 ++ip;
5818 break;
5820 case CEE_UNUSED56:
5821 case CEE_UNUSED57:
5822 case CEE_UNUSED70:
5823 case CEE_UNUSED:
5824 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5825 ++ip;
5826 break;
5827 case CEE_ENDFILTER:
5828 do_endfilter (&ctx);
5829 start = 1;
5830 ++ip;
5831 break;
5832 case CEE_UNALIGNED_:
5833 code_bounds_check (2);
5834 prefix |= PREFIX_UNALIGNED;
5835 ip += 2;
5836 break;
5837 case CEE_VOLATILE_:
5838 prefix |= PREFIX_VOLATILE;
5839 ++ip;
5840 break;
5841 case CEE_TAIL_:
5842 prefix |= PREFIX_TAIL;
5843 ++ip;
5844 if (ip < end && (*ip != CEE_CALL && *ip != CEE_CALLI && *ip != CEE_CALLVIRT))
5845 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("tail prefix must be used only with call opcodes at 0x%04x", ip_offset));
5846 break;
5848 case CEE_INITOBJ:
5849 code_bounds_check (5);
5850 do_initobj (&ctx, read32 (ip + 1));
5851 ip += 5;
5852 break;
5854 case CEE_CONSTRAINED_:
5855 code_bounds_check (5);
5856 ctx.constrained_type = get_boxable_mono_type (&ctx, read32 (ip + 1), "constrained.");
5857 prefix |= PREFIX_CONSTRAINED;
5858 ip += 5;
5859 break;
5861 case CEE_READONLY_:
5862 prefix |= PREFIX_READONLY;
5863 ip++;
5864 break;
5866 case CEE_CPBLK:
5867 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5868 if (!check_underflow (&ctx, 3))
5869 break;
5870 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction cpblk is not verifiable at 0x%04x", ctx.ip_offset));
5871 ip++;
5872 break;
5874 case CEE_INITBLK:
5875 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5876 if (!check_underflow (&ctx, 3))
5877 break;
5878 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction initblk is not verifiable at 0x%04x", ctx.ip_offset));
5879 ip++;
5880 break;
5882 case CEE_NO_:
5883 ip += 2;
5884 break;
5885 case CEE_RETHROW:
5886 if (!is_correct_rethrow (ctx.header, ip_offset))
5887 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("rethrow must be used inside a catch handler at 0x%04x", ctx.ip_offset));
5888 ctx.eval.size = 0;
5889 start = 1;
5890 ++ip;
5891 break;
5893 case CEE_SIZEOF:
5894 code_bounds_check (5);
5895 do_sizeof (&ctx, read32 (ip + 1));
5896 ip += 5;
5897 break;
5899 case CEE_REFANYTYPE:
5900 do_refanytype (&ctx);
5901 ++ip;
5902 break;
5904 default:
5905 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction FE %x at 0x%04x", *ip, ctx.ip_offset));
5906 ++ip;
5908 break;
5910 default:
5911 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ctx.ip_offset));
5912 ++ip;
5915 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
5916 if (prefix) {
5917 if (!ctx.prefix_set) //first prefix
5918 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
5919 ctx.prefix_set |= prefix;
5920 ctx.has_flags = TRUE;
5921 prefix = 0;
5922 } else {
5923 if (!ctx.has_flags)
5924 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
5926 if (ctx.prefix_set & PREFIX_CONSTRAINED)
5927 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after constrained prefix at 0x%04x", ctx.ip_offset));
5928 if (ctx.prefix_set & PREFIX_READONLY)
5929 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after readonly prefix at 0x%04x", ctx.ip_offset));
5930 if (ctx.prefix_set & PREFIX_VOLATILE)
5931 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after volatile prefix at 0x%04x", ctx.ip_offset));
5932 if (ctx.prefix_set & PREFIX_UNALIGNED)
5933 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after unaligned prefix at 0x%04x", ctx.ip_offset));
5934 ctx.prefix_set = prefix = 0;
5935 ctx.has_flags = FALSE;
5939 * if ip != end we overflowed: mark as error.
5941 if ((ip != end || !start) && ctx.verifiable && !ctx.list) {
5942 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Run ahead of method code at 0x%04x", ip_offset));
5945 /*We should guard against the last decoded opcode, otherwise we might add errors that doesn't make sense.*/
5946 for (i = 0; i < ctx.code_size && i < ip_offset; ++i) {
5947 if (ctx.code [i].flags & IL_CODE_FLAG_WAS_TARGET) {
5948 if (!(ctx.code [i].flags & IL_CODE_FLAG_SEEN))
5949 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or exception block target middle of intruction at 0x%04x", i));
5951 if (ctx.code [i].flags & IL_CODE_DELEGATE_SEQUENCE)
5952 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Branch to delegate code sequence at 0x%04x", i));
5954 if ((ctx.code [i].flags & IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL) && ctx.has_this_store)
5955 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at 0x%04x", i));
5957 if ((ctx.code [i].flags & IL_CODE_CALL_NONFINAL_VIRTUAL) && ctx.has_this_store)
5958 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));
5961 if (mono_method_is_constructor (ctx.method) && !ctx.super_ctor_called && !ctx.method->klass->valuetype && ctx.method->klass != mono_defaults.object_class) {
5962 char *method_name = mono_method_full_name (ctx.method, TRUE);
5963 char *type = mono_type_get_full_name (ctx.method->klass);
5964 if (ctx.method->klass->parent && mono_class_has_failure (ctx.method->klass->parent))
5965 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));
5966 else
5967 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Constructor %s for type %s not calling base type ctor.", method_name, type));
5968 g_free (method_name);
5969 g_free (type);
5972 cleanup:
5973 if (ctx.code) {
5974 for (i = 0; i < ctx.header->code_size; ++i) {
5975 if (ctx.code [i].stack)
5976 g_free (ctx.code [i].stack);
5980 for (tmp = ctx.funptrs; tmp; tmp = tmp->next)
5981 g_free (tmp->data);
5982 g_slist_free (ctx.funptrs);
5984 for (tmp = ctx.exception_types; tmp; tmp = tmp->next)
5985 mono_metadata_free_type ((MonoType *)tmp->data);
5986 g_slist_free (ctx.exception_types);
5988 for (i = 0; i < ctx.num_locals; ++i) {
5989 if (ctx.locals [i])
5990 mono_metadata_free_type (ctx.locals [i]);
5992 for (i = 0; i < ctx.max_args; ++i) {
5993 if (ctx.params [i])
5994 mono_metadata_free_type (ctx.params [i]);
5997 if (ctx.eval.stack)
5998 g_free (ctx.eval.stack);
5999 if (ctx.code)
6000 g_free (ctx.code);
6001 g_free (ctx.locals);
6002 g_free (ctx.params);
6003 mono_basic_block_free (original_bb);
6004 mono_metadata_free_mh (ctx.header);
6006 finish_collect_stats ();
6007 return ctx.list;
6010 char*
6011 mono_verify_corlib ()
6013 /* This is a public API function so cannot be removed */
6014 return NULL;
6018 * mono_verifier_is_enabled_for_method:
6019 * @method: the method to probe
6021 * Returns TRUE if @method needs to be verified.
6024 gboolean
6025 mono_verifier_is_enabled_for_method (MonoMethod *method)
6027 return mono_verifier_is_enabled_for_class (method->klass) && (method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD);
6031 * mono_verifier_is_enabled_for_class:
6032 * @klass: The `MonoClass` to probe
6034 * Returns TRUE if @klass need to be verified.
6037 gboolean
6038 mono_verifier_is_enabled_for_class (MonoClass *klass)
6040 return verify_all || (verifier_mode > MONO_VERIFIER_MODE_OFF && !(klass->image->assembly && klass->image->assembly->in_gac) && klass->image != mono_defaults.corlib);
6043 gboolean
6044 mono_verifier_is_enabled_for_image (MonoImage *image)
6046 return verify_all || verifier_mode > MONO_VERIFIER_MODE_OFF;
6050 * Dynamic methods are not considered full trust since if the user is trusted and need to
6051 * generate unsafe code, make the method skip verification - this is a known good way to do it.
6053 gboolean
6054 mono_verifier_is_method_full_trust (MonoMethod *method)
6056 return mono_verifier_is_class_full_trust (method->klass) && !method_is_dynamic (method);
6060 * Returns if @klass is under full trust or not.
6062 * TODO This code doesn't take CAS into account.
6064 * Under verify_all all user code must be verifiable if no security option was set
6067 gboolean
6068 mono_verifier_is_class_full_trust (MonoClass *klass)
6070 /* under CoreCLR code is trusted if it is part of the "platform" otherwise all code inside the GAC is trusted */
6071 gboolean trusted_location = !mono_security_core_clr_enabled () ?
6072 (klass->image->assembly && klass->image->assembly->in_gac) : mono_security_core_clr_is_platform_image (klass->image);
6074 if (verify_all && verifier_mode == MONO_VERIFIER_MODE_OFF)
6075 return trusted_location || klass->image == mono_defaults.corlib;
6076 return verifier_mode < MONO_VERIFIER_MODE_VERIFIABLE || trusted_location || klass->image == mono_defaults.corlib;
6079 GSList*
6080 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility, gboolean is_fulltrust)
6082 return mono_method_verify (method,
6083 (verifier_mode != MONO_VERIFIER_MODE_STRICT ? MONO_VERIFY_NON_STRICT: 0)
6084 | (!is_fulltrust && !mono_verifier_is_method_full_trust (method) ? MONO_VERIFY_FAIL_FAST : 0)
6085 | (skip_visibility ? MONO_VERIFY_SKIP_VISIBILITY : 0));
6088 static int
6089 get_field_end (MonoClassField *field)
6091 int align;
6092 int size = mono_type_size (field->type, &align);
6093 if (size == 0)
6094 size = 4; /*FIXME Is this a safe bet?*/
6095 return size + field->offset;
6098 static gboolean
6099 verify_class_for_overlapping_reference_fields (MonoClass *klass)
6101 int i = 0, j;
6102 gpointer iter = NULL;
6103 MonoClassField *field;
6104 gboolean is_fulltrust = mono_verifier_is_class_full_trust (klass);
6105 /*We can't skip types with !has_references since this is calculated after we have run.*/
6106 if (!mono_class_is_explicit_layout (klass))
6107 return TRUE;
6110 /*We must check for stuff overlapping reference fields.
6111 The outer loop uses mono_class_get_fields to ensure that MonoClass:fields get inited.
6113 while ((field = mono_class_get_fields (klass, &iter))) {
6114 int fieldEnd = get_field_end (field);
6115 gboolean is_valuetype = !MONO_TYPE_IS_REFERENCE (field->type);
6116 ++i;
6118 if (mono_field_is_deleted (field) || (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
6119 continue;
6121 int fcount = mono_class_get_field_count (klass);
6122 for (j = i; j < fcount; ++j) {
6123 MonoClassField *other = &klass->fields [j];
6124 int otherEnd = get_field_end (other);
6125 if (mono_field_is_deleted (other) || (is_valuetype && !MONO_TYPE_IS_REFERENCE (other->type)) || (other->type->attrs & FIELD_ATTRIBUTE_STATIC))
6126 continue;
6128 if (!is_valuetype && MONO_TYPE_IS_REFERENCE (other->type) && field->offset == other->offset && is_fulltrust)
6129 continue;
6131 if ((otherEnd > field->offset && otherEnd <= fieldEnd) || (other->offset >= field->offset && other->offset < fieldEnd))
6132 return FALSE;
6135 return TRUE;
6138 static guint
6139 field_hash (gconstpointer key)
6141 const MonoClassField *field = (const MonoClassField *)key;
6142 return g_str_hash (field->name) ^ mono_metadata_type_hash (field->type); /**/
6145 static gboolean
6146 field_equals (gconstpointer _a, gconstpointer _b)
6148 const MonoClassField *a = (const MonoClassField *)_a;
6149 const MonoClassField *b = (const MonoClassField *)_b;
6150 return !strcmp (a->name, b->name) && mono_metadata_type_equal (a->type, b->type);
6154 static gboolean
6155 verify_class_fields (MonoClass *klass)
6157 gpointer iter = NULL;
6158 MonoClassField *field;
6159 MonoGenericContext *context = mono_class_get_context (klass);
6160 GHashTable *unique_fields = g_hash_table_new_full (&field_hash, &field_equals, NULL, NULL);
6161 if (mono_class_is_gtd (klass))
6162 context = &mono_class_get_generic_container (klass)->context;
6164 while ((field = mono_class_get_fields (klass, &iter)) != NULL) {
6165 if (!mono_type_is_valid_type_in_context (field->type, context)) {
6166 g_hash_table_destroy (unique_fields);
6167 return FALSE;
6169 if (g_hash_table_lookup (unique_fields, field)) {
6170 g_hash_table_destroy (unique_fields);
6171 return FALSE;
6173 g_hash_table_insert (unique_fields, field, field);
6175 g_hash_table_destroy (unique_fields);
6176 return TRUE;
6179 static gboolean
6180 verify_interfaces (MonoClass *klass)
6182 int i;
6183 for (i = 0; i < klass->interface_count; ++i) {
6184 MonoClass *iface = klass->interfaces [i];
6185 if (!mono_class_get_flags (iface))
6186 return FALSE;
6188 return TRUE;
6191 static gboolean
6192 verify_valuetype_layout_with_target (MonoClass *klass, MonoClass *target_class)
6194 int type;
6195 gpointer iter = NULL;
6196 MonoClassField *field;
6197 MonoClass *field_class;
6199 if (!klass->valuetype)
6200 return TRUE;
6202 type = klass->byval_arg.type;
6203 /*primitive type fields are not properly decoded*/
6204 if ((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_R8) || (type >= MONO_TYPE_I && type <= MONO_TYPE_U))
6205 return TRUE;
6207 while ((field = mono_class_get_fields (klass, &iter)) != NULL) {
6208 if (!field->type)
6209 return FALSE;
6211 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
6212 continue;
6214 field_class = mono_class_get_generic_type_definition (mono_class_from_mono_type (field->type));
6216 if (field_class == target_class || klass == field_class || !verify_valuetype_layout_with_target (field_class, target_class))
6217 return FALSE;
6220 return TRUE;
6223 static gboolean
6224 verify_valuetype_layout (MonoClass *klass)
6226 gboolean res;
6227 res = verify_valuetype_layout_with_target (klass, klass);
6228 return res;
6231 static gboolean
6232 recursive_mark_constraint_args (MonoBitSet *used_args, MonoGenericContainer *gc, MonoType *type)
6234 int idx;
6235 MonoClass **constraints;
6236 MonoGenericParamInfo *param_info;
6238 g_assert (mono_type_is_generic_argument (type));
6240 idx = mono_type_get_generic_param_num (type);
6241 if (mono_bitset_test_fast (used_args, idx))
6242 return FALSE;
6244 mono_bitset_set_fast (used_args, idx);
6245 param_info = mono_generic_container_get_param_info (gc, idx);
6247 if (!param_info->constraints)
6248 return TRUE;
6250 for (constraints = param_info->constraints; *constraints; ++constraints) {
6251 MonoClass *ctr = *constraints;
6252 MonoType *constraint_type = &ctr->byval_arg;
6254 if (mono_type_is_generic_argument (constraint_type) && !recursive_mark_constraint_args (used_args, gc, constraint_type))
6255 return FALSE;
6257 return TRUE;
6260 static gboolean
6261 verify_generic_parameters (MonoClass *klass)
6263 int i;
6264 MonoGenericContainer *gc = mono_class_get_generic_container (klass);
6265 MonoBitSet *used_args = mono_bitset_new (gc->type_argc, 0);
6267 for (i = 0; i < gc->type_argc; ++i) {
6268 MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
6269 MonoClass **constraints;
6271 if (!param_info->constraints)
6272 continue;
6274 mono_bitset_clear_all (used_args);
6275 mono_bitset_set_fast (used_args, i);
6277 for (constraints = param_info->constraints; *constraints; ++constraints) {
6278 MonoClass *ctr = *constraints;
6279 MonoType *constraint_type = &ctr->byval_arg;
6281 if (!mono_class_can_access_class (klass, ctr))
6282 goto fail;
6284 if (!mono_type_is_valid_type_in_context (constraint_type, &gc->context))
6285 goto fail;
6287 if (mono_type_is_generic_argument (constraint_type) && !recursive_mark_constraint_args (used_args, gc, constraint_type))
6288 goto fail;
6289 if (mono_class_is_ginst (ctr) && !mono_class_is_valid_generic_instantiation (NULL, ctr))
6290 goto fail;
6293 mono_bitset_free (used_args);
6294 return TRUE;
6296 fail:
6297 mono_bitset_free (used_args);
6298 return FALSE;
6302 * Check if the class is verifiable.
6304 * Right now there are no conditions that make a class a valid but not verifiable. Both overlapping reference
6305 * field and invalid generic instantiation are fatal errors.
6307 * This method must be safe to be called from mono_class_init and all code must be carefull about that.
6310 gboolean
6311 mono_verifier_verify_class (MonoClass *klass)
6313 /*Neither <Module>, object or ifaces have parent.*/
6314 if (!klass->parent &&
6315 klass != mono_defaults.object_class &&
6316 !MONO_CLASS_IS_INTERFACE (klass) &&
6317 (!image_is_dynamic (klass->image) && klass->type_token != 0x2000001)) /*<Module> is the first type in the assembly*/
6318 return FALSE;
6319 if (klass->parent) {
6320 if (MONO_CLASS_IS_INTERFACE (klass->parent))
6321 return FALSE;
6322 if (!mono_class_is_ginst (klass) && mono_class_is_gtd (klass->parent))
6323 return FALSE;
6324 if (mono_class_is_ginst (klass->parent) && !mono_class_is_ginst (klass)) {
6325 MonoGenericContext *context = mono_class_get_context (klass);
6326 if (mono_class_is_gtd (klass))
6327 context = &mono_class_get_generic_container (klass)->context;
6328 if (!mono_type_is_valid_type_in_context (&klass->parent->byval_arg, context))
6329 return FALSE;
6332 if (mono_class_is_gtd (klass) && (mono_class_is_explicit_layout (klass)))
6333 return FALSE;
6334 if (mono_class_is_gtd (klass) && !verify_generic_parameters (klass))
6335 return FALSE;
6336 if (!verify_class_for_overlapping_reference_fields (klass))
6337 return FALSE;
6338 if (mono_class_is_ginst (klass) && !mono_class_is_valid_generic_instantiation (NULL, klass))
6339 return FALSE;
6340 if (!mono_class_is_ginst (klass) && !verify_class_fields (klass))
6341 return FALSE;
6342 if (klass->valuetype && !verify_valuetype_layout (klass))
6343 return FALSE;
6344 if (!verify_interfaces (klass))
6345 return FALSE;
6346 return TRUE;
6349 gboolean
6350 mono_verifier_class_is_valid_generic_instantiation (MonoClass *klass)
6352 return mono_class_is_valid_generic_instantiation (NULL, klass);
6355 gboolean
6356 mono_verifier_is_method_valid_generic_instantiation (MonoMethod *method)
6358 if (!method->is_inflated)
6359 return TRUE;
6360 return mono_method_is_valid_generic_instantiation (NULL, method);
6363 #else
6365 gboolean
6366 mono_verifier_verify_class (MonoClass *klass)
6368 /* The verifier was disabled at compile time */
6369 return TRUE;
6372 GSList*
6373 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility, gboolean is_fulltrust)
6375 /* The verifier was disabled at compile time */
6376 return NULL;
6379 gboolean
6380 mono_verifier_is_class_full_trust (MonoClass *klass)
6382 /* The verifier was disabled at compile time */
6383 return TRUE;
6386 gboolean
6387 mono_verifier_is_method_full_trust (MonoMethod *method)
6389 /* The verifier was disabled at compile time */
6390 return TRUE;
6393 gboolean
6394 mono_verifier_is_enabled_for_image (MonoImage *image)
6396 /* The verifier was disabled at compile time */
6397 return FALSE;
6400 gboolean
6401 mono_verifier_is_enabled_for_class (MonoClass *klass)
6403 /* The verifier was disabled at compile time */
6404 return FALSE;
6407 gboolean
6408 mono_verifier_is_enabled_for_method (MonoMethod *method)
6410 /* The verifier was disabled at compile time */
6411 return FALSE;
6414 GSList*
6415 mono_method_verify (MonoMethod *method, int level)
6417 /* The verifier was disabled at compile time */
6418 return NULL;
6421 void
6422 mono_free_verify_list (GSList *list)
6424 /* The verifier was disabled at compile time */
6425 /* will always be null if verifier is disabled */
6428 gboolean
6429 mono_verifier_class_is_valid_generic_instantiation (MonoClass *klass)
6431 return TRUE;
6434 gboolean
6435 mono_verifier_is_method_valid_generic_instantiation (MonoMethod *method)
6437 return TRUE;
6442 #endif