mono_class_enum_basetype to mono_class_enum_basetype_internal to skip GC mode machine...
[mono-project.git] / mono / metadata / verify.c
blobac0f0729357361250b5c8e4eb2e9a9311f965f0f
1 /**
2 * \file
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/class-init.h>
27 #include <mono/metadata/security-manager.h>
28 #include <mono/metadata/security-core-clr.h>
29 #include <mono/metadata/tokentype.h>
30 #include <mono/metadata/mono-basic-block.h>
31 #include <mono/metadata/attrdefs.h>
32 #include <mono/utils/mono-counters.h>
33 #include <mono/utils/monobitset.h>
34 #include <mono/utils/mono-error-internals.h>
35 #include <string.h>
36 #include <ctype.h>
38 static MiniVerifierMode verifier_mode = MONO_VERIFIER_MODE_OFF;
39 static gboolean verify_all = FALSE;
42 * Set the desired level of checks for the verfier.
45 void
46 mono_verifier_set_mode (MiniVerifierMode mode)
48 verifier_mode = mode;
51 void
52 mono_verifier_enable_verify_all ()
54 verify_all = TRUE;
57 #ifndef DISABLE_VERIFIER
59 * Pull the list of opcodes
61 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
62 a = i,
64 enum {
65 #include "mono/cil/opcode.def"
66 LAST = 0xff
68 #undef OPDEF
70 #ifdef MONO_VERIFIER_DEBUG
71 #define VERIFIER_DEBUG(code) do { code } while (0)
72 #else
73 #define VERIFIER_DEBUG(code)
74 #endif
76 //////////////////////////////////////////////////////////////////
77 #define IS_STRICT_MODE(ctx) (((ctx)->level & MONO_VERIFY_NON_STRICT) == 0)
78 #define IS_FAIL_FAST_MODE(ctx) (((ctx)->level & MONO_VERIFY_FAIL_FAST) == MONO_VERIFY_FAIL_FAST)
79 #define IS_SKIP_VISIBILITY(ctx) (((ctx)->level & MONO_VERIFY_SKIP_VISIBILITY) == MONO_VERIFY_SKIP_VISIBILITY)
80 #define IS_REPORT_ALL_ERRORS(ctx) (((ctx)->level & MONO_VERIFY_REPORT_ALL_ERRORS) == MONO_VERIFY_REPORT_ALL_ERRORS)
81 #define CLEAR_PREFIX(ctx, prefix) do { (ctx)->prefix_set &= ~(prefix); } while (0)
82 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
83 do { \
84 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
85 vinfo->info.status = __status; \
86 vinfo->info.message = ( __msg ); \
87 vinfo->exception_type = (__exception); \
88 (__ctx)->list = g_slist_prepend ((__ctx)->list, vinfo); \
89 } while (0)
91 //TODO support MONO_VERIFY_REPORT_ALL_ERRORS
92 #define ADD_VERIFY_ERROR(__ctx, __msg) \
93 do { \
94 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
95 (__ctx)->valid = 0; \
96 } while (0)
98 #define CODE_NOT_VERIFIABLE(__ctx, __msg) \
99 do { \
100 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
101 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, MONO_EXCEPTION_UNVERIFIABLE_IL); \
102 (__ctx)->verifiable = 0; \
103 if (IS_FAIL_FAST_MODE (__ctx)) \
104 (__ctx)->valid = 0; \
106 } while (0)
108 #define ADD_VERIFY_ERROR2(__ctx, __msg, __exception) \
109 do { \
110 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, __exception); \
111 (__ctx)->valid = 0; \
112 } while (0)
114 #define CODE_NOT_VERIFIABLE2(__ctx, __msg, __exception) \
115 do { \
116 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
117 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, __exception); \
118 (__ctx)->verifiable = 0; \
119 if (IS_FAIL_FAST_MODE (__ctx)) \
120 (__ctx)->valid = 0; \
122 } while (0)
124 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
125 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
127 #if SIZEOF_VOID_P == 4
128 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
129 #else
130 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
131 #endif
133 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
134 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
136 /*Flags to be used with ILCodeDesc::flags */
137 enum {
138 /*Instruction has not been processed.*/
139 IL_CODE_FLAG_NOT_PROCESSED = 0,
140 /*Instruction was decoded by mono_method_verify loop.*/
141 IL_CODE_FLAG_SEEN = 1,
142 /*Instruction was target of a branch or is at a protected block boundary.*/
143 IL_CODE_FLAG_WAS_TARGET = 2,
144 /*Used by stack_init to avoid double initialize each entry.*/
145 IL_CODE_FLAG_STACK_INITED = 4,
146 /*Used by merge_stacks to decide if it should just copy the eval stack.*/
147 IL_CODE_STACK_MERGED = 8,
148 /*This instruction is part of the delegate construction sequence, it cannot be target of a branch.*/
149 IL_CODE_DELEGATE_SEQUENCE = 0x10,
150 /*This is a delegate created from a ldftn to a non final virtual method*/
151 IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL = 0x20,
152 /*This is a call to a non final virtual method*/
153 IL_CODE_CALL_NONFINAL_VIRTUAL = 0x40,
156 typedef enum {
157 RESULT_VALID,
158 RESULT_UNVERIFIABLE,
159 RESULT_INVALID
160 } verify_result_t;
162 typedef struct {
163 MonoType *type;
164 int stype;
165 MonoMethod *method;
166 } ILStackDesc;
169 typedef struct {
170 ILStackDesc *stack;
171 guint16 size, max_size;
172 guint16 flags;
173 } ILCodeDesc;
175 typedef struct {
176 int max_args;
177 int max_stack;
178 int verifiable;
179 int valid;
180 int level;
182 int code_size;
183 ILCodeDesc *code;
184 ILCodeDesc eval;
186 MonoType **params;
187 GSList *list;
188 /*Allocated fnptr MonoType that should be freed by us.*/
189 GSList *funptrs;
190 /*Type dup'ed exception types from catch blocks.*/
191 GSList *exception_types;
193 int num_locals;
194 MonoType **locals;
195 char *locals_verification_state;
197 /*TODO get rid of target here, need_merge in mono_method_verify and hoist the merging code in the branching code*/
198 int target;
200 guint32 ip_offset;
201 MonoMethodSignature *signature;
202 MonoMethodHeader *header;
204 MonoGenericContext *generic_context;
205 MonoImage *image;
206 MonoMethod *method;
208 /*This flag helps solving a corner case of delegate verification in that you cannot have a "starg 0"
209 *on a method that creates a delegate for a non-final virtual method using ldftn*/
210 gboolean has_this_store;
212 /*This flag is used to control if the contructor of the parent class has been called.
213 *If the this pointer is pushed on the eval stack and it's a reference type constructor and
214 * super_ctor_called is false, the uninitialized flag is set on the pushed value.
216 * Poping an uninitialized this ptr from the eval stack is an unverifiable operation unless
217 * the safe variant is used. Only a few opcodes can use it : dup, pop, ldfld, stfld and call to a constructor.
219 gboolean super_ctor_called;
221 guint32 prefix_set;
222 gboolean has_flags;
223 MonoType *constrained_type;
224 } VerifyContext;
226 static void
227 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external);
229 static int
230 get_stack_type (MonoType *type);
232 static gboolean
233 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn);
235 static gboolean
236 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass);
238 static gboolean
239 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method);
241 static MonoGenericParam*
242 verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type);
244 static gboolean
245 verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate);
246 //////////////////////////////////////////////////////////////////
250 enum {
251 TYPE_INV = 0, /* leave at 0. */
252 TYPE_I4 = 1,
253 TYPE_I8 = 2,
254 TYPE_NATIVE_INT = 3,
255 TYPE_R8 = 4,
256 /* Used by operator tables to resolve pointer types (managed & unmanaged) and by unmanaged pointer types*/
257 TYPE_PTR = 5,
258 /* value types and classes */
259 TYPE_COMPLEX = 6,
260 /* Number of types, used to define the size of the tables*/
261 TYPE_MAX = 6,
263 /* Used by tables to signal that a result is not verifiable*/
264 NON_VERIFIABLE_RESULT = 0x80,
266 /*Mask used to extract just the type, excluding flags */
267 TYPE_MASK = 0x0F,
269 /* The stack type is a managed pointer, unmask the value to res */
270 POINTER_MASK = 0x100,
272 /*Stack type with the pointer mask*/
273 RAW_TYPE_MASK = 0x10F,
275 /* Controlled Mutability Manager Pointer */
276 CMMP_MASK = 0x200,
278 /* The stack type is a null literal*/
279 NULL_LITERAL_MASK = 0x400,
281 /**Used by ldarg.0 and family to let delegate verification happens.*/
282 THIS_POINTER_MASK = 0x800,
284 /**Signals that this is a boxed value type*/
285 BOXED_MASK = 0x1000,
287 /*This is an unitialized this ref*/
288 UNINIT_THIS_MASK = 0x2000,
290 /* This is a safe to return byref */
291 SAFE_BYREF_MASK = 0x4000,
294 static const char* const
295 type_names [TYPE_MAX + 1] = {
296 "Invalid",
297 "Int32",
298 "Int64",
299 "Native Int",
300 "Float64",
301 "Native Pointer",
302 "Complex"
305 enum {
306 PREFIX_UNALIGNED = 1,
307 PREFIX_VOLATILE = 2,
308 PREFIX_TAIL = 4,
309 PREFIX_CONSTRAINED = 8,
310 PREFIX_READONLY = 16
312 //////////////////////////////////////////////////////////////////
314 #ifdef ENABLE_VERIFIER_STATS
316 #define _MEM_ALLOC(amt) do { allocated_memory += (amt); working_set += (amt); } while (0)
317 #define _MEM_FREE(amt) do { working_set -= (amt); } while (0)
319 static int allocated_memory;
320 static int working_set;
321 static int max_allocated_memory;
322 static int max_working_set;
323 static int total_allocated_memory;
325 static void
326 finish_collect_stats (void)
328 max_allocated_memory = MAX (max_allocated_memory, allocated_memory);
329 max_working_set = MAX (max_working_set, working_set);
330 total_allocated_memory += allocated_memory;
331 allocated_memory = working_set = 0;
334 static void
335 init_verifier_stats (void)
337 static gboolean inited;
338 if (!inited) {
339 inited = TRUE;
340 mono_counters_register ("Maximum memory allocated during verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &max_allocated_memory);
341 mono_counters_register ("Maximum memory used during verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &max_working_set);
342 mono_counters_register ("Total memory allocated for verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &total_allocated_memory);
346 #else
348 #define _MEM_ALLOC(amt) do {} while (0)
349 #define _MEM_FREE(amt) do { } while (0)
351 #define finish_collect_stats()
352 #define init_verifier_stats()
354 #endif
357 //////////////////////////////////////////////////////////////////
360 * Verify if @token refers to a valid row on int's table.
362 static gboolean
363 token_bounds_check (MonoImage *image, guint32 token)
365 if (image_is_dynamic (image))
366 return mono_dynamic_image_is_valid_token ((MonoDynamicImage*)image, token);
367 return image->tables [mono_metadata_token_table (token)].rows >= mono_metadata_token_index (token) && mono_metadata_token_index (token) > 0;
370 static MonoType *
371 mono_type_create_fnptr_from_mono_method (VerifyContext *ctx, MonoMethod *method)
373 MonoType *res = g_new0 (MonoType, 1);
374 _MEM_ALLOC (sizeof (MonoType));
376 //FIXME use mono_method_get_signature_full
377 res->data.method = mono_method_signature (method);
378 res->type = MONO_TYPE_FNPTR;
379 ctx->funptrs = g_slist_prepend (ctx->funptrs, res);
380 return res;
384 * mono_type_is_enum_type:
386 * Returns: TRUE if @type is an enum type.
388 static gboolean
389 mono_type_is_enum_type (MonoType *type)
391 if (type->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (type->data.klass))
392 return TRUE;
393 if (type->type == MONO_TYPE_GENERICINST && m_class_is_enumtype (type->data.generic_class->container_class))
394 return TRUE;
395 return FALSE;
399 * mono_type_is_value_type:
401 * Returns: TRUE if @type is named after @namespace.@name.
404 static gboolean
405 mono_type_is_value_type (MonoType *type, const char *namespace_, const char *name)
407 return type->type == MONO_TYPE_VALUETYPE &&
408 !strcmp (namespace_, m_class_get_name_space (type->data.klass)) &&
409 !strcmp (name, m_class_get_name (type->data.klass));
413 * Returns TURE if @type is VAR or MVAR
415 static gboolean
416 mono_type_is_generic_argument (MonoType *type)
418 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
422 * mono_type_get_underlying_type_any:
424 * This functions is just like mono_type_get_underlying_type but it doesn't care if the type is byref.
426 * Returns the underlying type of @type regardless if it is byref or not.
428 static MonoType*
429 mono_type_get_underlying_type_any (MonoType *type)
431 if (type->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (type->data.klass))
432 return mono_class_enum_basetype_internal (type->data.klass);
433 if (type->type == MONO_TYPE_GENERICINST && m_class_is_enumtype (type->data.generic_class->container_class))
434 return mono_class_enum_basetype_internal (type->data.generic_class->container_class);
435 return type;
438 static G_GNUC_UNUSED const char*
439 mono_type_get_stack_name (MonoType *type)
441 return type_names [get_stack_type (type) & TYPE_MASK];
444 #define CTOR_REQUIRED_FLAGS (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_RT_SPECIAL_NAME)
445 #define CTOR_INVALID_FLAGS (METHOD_ATTRIBUTE_STATIC)
447 static gboolean
448 mono_method_is_constructor (MonoMethod *method)
450 return ((method->flags & CTOR_REQUIRED_FLAGS) == CTOR_REQUIRED_FLAGS &&
451 !(method->flags & CTOR_INVALID_FLAGS) &&
452 !strcmp (".ctor", method->name));
455 static gboolean
456 mono_class_has_default_constructor (MonoClass *klass)
458 MonoMethod *method;
459 int i;
461 mono_class_setup_methods (klass);
462 if (mono_class_has_failure (klass))
463 return FALSE;
465 int mcount = mono_class_get_method_count (klass);
466 MonoMethod **klass_methods = m_class_get_methods (klass);
467 for (i = 0; i < mcount; ++i) {
468 method = klass_methods [i];
469 if (mono_method_is_constructor (method) &&
470 mono_method_signature (method) &&
471 mono_method_signature (method)->param_count == 0 &&
472 (method->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC)
473 return TRUE;
475 return FALSE;
479 * Verify if @type is valid for the given @ctx verification context.
480 * this function checks for VAR and MVAR types that are invalid under the current verifier,
482 static gboolean
483 mono_type_is_valid_type_in_context_full (MonoType *type, MonoGenericContext *context, gboolean check_gtd)
485 int i;
486 MonoGenericInst *inst;
488 switch (type->type) {
489 case MONO_TYPE_VAR:
490 case MONO_TYPE_MVAR:
491 if (!context)
492 return FALSE;
493 inst = type->type == MONO_TYPE_VAR ? context->class_inst : context->method_inst;
494 if (!inst || mono_type_get_generic_param_num (type) >= inst->type_argc)
495 return FALSE;
496 break;
497 case MONO_TYPE_SZARRAY:
498 return mono_type_is_valid_type_in_context_full (m_class_get_byval_arg (type->data.klass), context, check_gtd);
499 case MONO_TYPE_ARRAY:
500 return mono_type_is_valid_type_in_context_full (m_class_get_byval_arg (type->data.array->eklass), context, check_gtd);
501 case MONO_TYPE_PTR:
502 return mono_type_is_valid_type_in_context_full (type->data.type, context, check_gtd);
503 case MONO_TYPE_GENERICINST:
504 inst = type->data.generic_class->context.class_inst;
505 if (!inst->is_open)
506 break;
507 for (i = 0; i < inst->type_argc; ++i)
508 if (!mono_type_is_valid_type_in_context_full (inst->type_argv [i], context, check_gtd))
509 return FALSE;
510 break;
511 case MONO_TYPE_CLASS:
512 case MONO_TYPE_VALUETYPE: {
513 MonoClass *klass = type->data.klass;
514 MonoType *klass_byval_arg = m_class_get_byval_arg (klass);
516 * It's possible to encode generic'sh types in such a way that they disguise themselves as class or valuetype.
517 * Fixing the type decoding is really tricky since under some cases this behavior is needed, for example, to
518 * have a 'class' type pointing to a 'genericinst' class.
520 * For the runtime these non canonical (weird) encodings work fine, the worst they can cause is some
521 * reflection oddities which are harmless - to security at least.
523 if (klass_byval_arg->type != type->type)
524 return mono_type_is_valid_type_in_context_full (klass_byval_arg, context, check_gtd);
526 if (check_gtd && mono_class_is_gtd (klass))
527 return FALSE;
528 break;
530 default:
531 break;
533 return TRUE;
536 static gboolean
537 mono_type_is_valid_type_in_context (MonoType *type, MonoGenericContext *context)
539 return mono_type_is_valid_type_in_context_full (type, context, FALSE);
542 /*This function returns NULL if the type is not instantiatable*/
543 static MonoType*
544 verifier_inflate_type (VerifyContext *ctx, MonoType *type, MonoGenericContext *context)
546 ERROR_DECL (error);
547 MonoType *result;
549 result = mono_class_inflate_generic_type_checked (type, context, error);
550 if (!mono_error_ok (error)) {
551 mono_error_cleanup (error);
552 return NULL;
554 return result;
557 /*A side note here. We don't need to check if arguments are broken since this
558 is only need to be done by the runtime before realizing the type.
560 static gboolean
561 is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
563 ERROR_DECL (error);
564 int i;
566 if (ginst->type_argc != gc->type_argc)
567 return FALSE;
569 for (i = 0; i < gc->type_argc; ++i) {
570 MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
571 MonoClass *paramClass;
572 MonoClass **constraints;
573 MonoType *param_type = ginst->type_argv [i];
575 /*it's not our job to validate type variables*/
576 if (mono_type_is_generic_argument (param_type))
577 continue;
579 paramClass = mono_class_from_mono_type (param_type);
582 /* A GTD can't be a generic argument.
584 * Due to how types are encoded we must check for the case of a genericinst MonoType and GTD MonoClass.
585 * This happens in cases such as: class Foo<T> { void X() { new Bar<T> (); } }
587 * Open instantiations can have GTDs as this happens when one type is instantiated with others params
588 * and the former has an expansion into the later. For example:
589 * class B<K> {}
590 * class A<T>: B<K> {}
591 * The type A <K> has a parent B<K>, that is inflated into the GTD B<>.
592 * Since A<K> is open, thus not instantiatable, this is valid.
594 if (mono_class_is_gtd (paramClass) && param_type->type != MONO_TYPE_GENERICINST && !ginst->is_open)
595 return FALSE;
597 /*it's not safe to call mono_class_init from here*/
598 if (mono_class_is_ginst (paramClass) && !m_class_is_inited (paramClass)) {
599 if (!mono_class_is_valid_generic_instantiation (NULL, paramClass))
600 return FALSE;
603 if (!param_info->constraints && !(param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK))
604 continue;
606 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && (!m_class_is_valuetype (paramClass) || mono_class_is_nullable (paramClass)))
607 return FALSE;
609 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && m_class_is_valuetype (paramClass))
610 return FALSE;
612 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !m_class_is_valuetype (paramClass) && !mono_class_has_default_constructor (paramClass))
613 return FALSE;
615 if (!param_info->constraints)
616 continue;
618 for (constraints = param_info->constraints; *constraints; ++constraints) {
619 MonoClass *ctr = *constraints;
620 MonoType *inflated;
622 inflated = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (ctr), context, error);
623 if (!mono_error_ok (error)) {
624 mono_error_cleanup (error);
625 return FALSE;
627 ctr = mono_class_from_mono_type (inflated);
628 mono_metadata_free_type (inflated);
630 /*FIXME maybe we need the same this as verifier_class_is_assignable_from*/
631 if (!mono_class_is_assignable_from_slow (ctr, paramClass))
632 return FALSE;
635 return TRUE;
639 * mono_generic_param_is_constraint_compatible:
641 * \returns TRUE if \p candidate is constraint compatible with \p target.
643 * This means that \p candidate constraints are a super set of \p target constaints
645 static gboolean
646 mono_generic_param_is_constraint_compatible (VerifyContext *ctx, MonoGenericParam *target, MonoGenericParam *candidate, MonoClass *candidate_param_class, MonoGenericContext *context)
648 MonoGenericParamInfo *tinfo = mono_generic_param_info (target);
649 MonoGenericParamInfo *cinfo = mono_generic_param_info (candidate);
650 MonoClass **candidate_class;
651 gboolean class_constraint_satisfied = FALSE;
652 gboolean valuetype_constraint_satisfied = FALSE;
654 int tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
655 int cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
657 if (cinfo->constraints) {
658 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
659 MonoClass *cc;
660 MonoType *inflated = verifier_inflate_type (ctx, m_class_get_byval_arg (*candidate_class), ctx->generic_context);
661 if (!inflated)
662 return FALSE;
663 cc = mono_class_from_mono_type (inflated);
664 mono_metadata_free_type (inflated);
666 if (mono_type_is_reference (m_class_get_byval_arg (cc)) && !MONO_CLASS_IS_INTERFACE (cc))
667 class_constraint_satisfied = TRUE;
668 else if (!mono_type_is_reference (m_class_get_byval_arg (cc)) && !MONO_CLASS_IS_INTERFACE (cc))
669 valuetype_constraint_satisfied = TRUE;
672 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
673 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
675 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
676 return FALSE;
677 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
678 return FALSE;
679 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
680 valuetype_constraint_satisfied)) {
681 return FALSE;
685 if (tinfo->constraints) {
686 MonoClass **target_class;
687 for (target_class = tinfo->constraints; *target_class; ++target_class) {
688 MonoClass *tc;
689 MonoType *inflated = verifier_inflate_type (ctx, m_class_get_byval_arg (*target_class), context);
690 if (!inflated)
691 return FALSE;
692 tc = mono_class_from_mono_type (inflated);
693 mono_metadata_free_type (inflated);
696 * A constraint from @target might inflate into @candidate itself and in that case we don't need
697 * check it's constraints since it satisfy the constraint by itself.
699 if (mono_metadata_type_equal (m_class_get_byval_arg (tc), m_class_get_byval_arg (candidate_param_class)))
700 continue;
702 if (!cinfo->constraints)
703 return FALSE;
705 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
706 MonoClass *cc;
707 inflated = verifier_inflate_type (ctx, m_class_get_byval_arg (*candidate_class), ctx->generic_context);
708 if (!inflated)
709 return FALSE;
710 cc = mono_class_from_mono_type (inflated);
711 mono_metadata_free_type (inflated);
713 if (verifier_class_is_assignable_from (tc, cc))
714 break;
717 * This happens when we have the following:
719 * Bar<K> where K : IFace
720 * Foo<T, U> where T : U where U : IFace
721 * ...
722 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
725 if (mono_type_is_generic_argument (m_class_get_byval_arg (cc))) {
726 MonoGenericParam *other_candidate = verifier_get_generic_param_from_type (ctx, m_class_get_byval_arg (cc));
728 if (mono_generic_param_is_constraint_compatible (ctx, target, other_candidate, cc, context)) {
729 break;
733 if (!*candidate_class)
734 return FALSE;
737 return TRUE;
740 static MonoGenericParam*
741 verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type)
743 MonoGenericContainer *gc;
744 MonoMethod *method = ctx->method;
745 int num;
747 num = mono_type_get_generic_param_num (type);
749 if (type->type == MONO_TYPE_VAR) {
750 MonoClass *gtd = method->klass;
751 if (mono_class_is_ginst (gtd))
752 gtd = mono_class_get_generic_class (gtd)->container_class;
753 gc = mono_class_try_get_generic_container (gtd);
754 } else { //MVAR
755 MonoMethod *gmd = method;
756 if (method->is_inflated)
757 gmd = ((MonoMethodInflated*)method)->declaring;
758 gc = mono_method_get_generic_container (gmd);
760 if (!gc)
761 return NULL;
762 return mono_generic_container_get_param (gc, num);
768 * Verify if @type is valid for the given @ctx verification context.
769 * this function checks for VAR and MVAR types that are invalid under the current verifier,
770 * This means that it either
772 static gboolean
773 is_valid_type_in_context (VerifyContext *ctx, MonoType *type)
775 return mono_type_is_valid_type_in_context (type, ctx->generic_context);
778 static gboolean
779 is_valid_generic_instantiation_in_context (VerifyContext *ctx, MonoGenericInst *ginst, gboolean check_gtd)
781 int i;
782 for (i = 0; i < ginst->type_argc; ++i) {
783 MonoType *type = ginst->type_argv [i];
785 if (!mono_type_is_valid_type_in_context_full (type, ctx->generic_context, TRUE))
786 return FALSE;
788 return TRUE;
791 static gboolean
792 generic_arguments_respect_constraints (VerifyContext *ctx, MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
794 int i;
795 for (i = 0; i < ginst->type_argc; ++i) {
796 MonoType *type = ginst->type_argv [i];
797 MonoGenericParam *target = mono_generic_container_get_param (gc, i);
798 MonoGenericParam *candidate;
799 MonoClass *candidate_class;
801 if (!mono_type_is_generic_argument (type))
802 continue;
804 if (!is_valid_type_in_context (ctx, type))
805 return FALSE;
807 candidate = verifier_get_generic_param_from_type (ctx, type);
808 candidate_class = mono_class_from_mono_type (type);
810 if (!mono_generic_param_is_constraint_compatible (ctx, target, candidate, candidate_class, context))
811 return FALSE;
813 return TRUE;
816 static gboolean
817 mono_method_repect_method_constraints (VerifyContext *ctx, MonoMethod *method)
819 MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
820 MonoGenericInst *ginst = gmethod->context.method_inst;
821 MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
822 return !gc || generic_arguments_respect_constraints (ctx, gc, &gmethod->context, ginst);
825 static gboolean
826 mono_class_repect_method_constraints (VerifyContext *ctx, MonoClass *klass)
828 MonoGenericClass *gklass = mono_class_get_generic_class (klass);
829 MonoGenericInst *ginst = gklass->context.class_inst;
830 MonoGenericContainer *gc = mono_class_get_generic_container (gklass->container_class);
831 return !gc || generic_arguments_respect_constraints (ctx, gc, &gklass->context, ginst);
834 static gboolean
835 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method)
837 MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
838 MonoGenericInst *ginst = gmethod->context.method_inst;
839 MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
840 if (!gc) /*non-generic inflated method - it's part of a generic type */
841 return TRUE;
842 if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst, TRUE))
843 return FALSE;
844 return is_valid_generic_instantiation (gc, &gmethod->context, ginst);
848 static gboolean
849 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass)
851 MonoGenericClass *gklass = mono_class_get_generic_class (klass);
852 MonoGenericInst *ginst = gklass->context.class_inst;
853 MonoGenericContainer *gc = mono_class_get_generic_container (gklass->container_class);
854 if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst, TRUE))
855 return FALSE;
856 return is_valid_generic_instantiation (gc, &gklass->context, ginst);
859 static gboolean
860 mono_type_is_valid_in_context (VerifyContext *ctx, MonoType *type)
862 MonoClass *klass;
864 if (type == NULL) {
865 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid null type at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
866 return FALSE;
869 if (!is_valid_type_in_context (ctx, type)) {
870 char *str = mono_type_full_name (type);
871 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type (%s%s) (argument out of range or %s is not generic) at 0x%04x",
872 str [0] == '!' ? "" : type->type == MONO_TYPE_VAR ? "!" : "!!",
873 str,
874 type->type == MONO_TYPE_VAR ? "class" : "method",
875 ctx->ip_offset),
876 MONO_EXCEPTION_BAD_IMAGE);
877 g_free (str);
878 return FALSE;
881 klass = mono_class_from_mono_type (type);
882 mono_class_init (klass);
883 if (mono_class_has_failure (klass)) {
884 if (mono_class_is_ginst (klass) && !mono_class_is_valid_generic_instantiation (NULL, klass))
885 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic instantiation of type %s.%s at 0x%04x", m_class_get_name_space (klass), m_class_get_name (klass), ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
886 else
887 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Could not load type %s.%s at 0x%04x", m_class_get_name_space (klass), m_class_get_name (klass), ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
888 return FALSE;
891 if (mono_class_is_ginst (klass) && mono_class_has_failure (mono_class_get_generic_class (klass)->container_class)) {
892 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Could not load type %s.%s at 0x%04x", m_class_get_name_space (klass), m_class_get_name (klass), ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
893 return FALSE;
896 if (!mono_class_is_ginst (klass))
897 return TRUE;
899 if (!mono_class_is_valid_generic_instantiation (ctx, klass)) {
900 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type instantiation of type %s.%s at 0x%04x", m_class_get_name_space (klass), m_class_get_name (klass), ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
901 return FALSE;
904 if (!mono_class_repect_method_constraints (ctx, klass)) {
905 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", m_class_get_name_space (klass), m_class_get_name (klass), ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
906 return FALSE;
909 return TRUE;
912 static verify_result_t
913 mono_method_is_valid_in_context (VerifyContext *ctx, MonoMethod *method)
915 if (!mono_type_is_valid_in_context (ctx, m_class_get_byval_arg (method->klass)))
916 return RESULT_INVALID;
918 if (!method->is_inflated)
919 return RESULT_VALID;
921 if (!mono_method_is_valid_generic_instantiation (ctx, method)) {
922 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic method instantiation of method %s.%s::%s at 0x%04x", m_class_get_name_space (method->klass), m_class_get_name (method->klass), method->name, ctx->ip_offset), MONO_EXCEPTION_UNVERIFIABLE_IL);
923 return RESULT_INVALID;
926 if (!mono_method_repect_method_constraints (ctx, method)) {
927 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", m_class_get_name_space (method->klass), m_class_get_name (method->klass), method->name, ctx->ip_offset));
928 return RESULT_UNVERIFIABLE;
930 return RESULT_VALID;
934 static MonoClassField*
935 verifier_load_field (VerifyContext *ctx, int token, MonoClass **out_klass, const char *opcode) {
936 ERROR_DECL (error);
937 MonoClassField *field;
938 MonoClass *klass = NULL;
940 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
941 field = (MonoClassField *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
942 klass = field ? field->parent : NULL;
943 } else {
944 if (!IS_FIELD_DEF_OR_REF (token) || !token_bounds_check (ctx->image, token)) {
945 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid field token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
946 return NULL;
949 field = mono_field_from_token_checked (ctx->image, token, &klass, ctx->generic_context, error);
950 mono_error_cleanup (error); /*FIXME don't swallow the error */
953 if (!field || !field->parent || !klass) {
954 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);
955 return NULL;
958 if (!mono_type_is_valid_in_context (ctx, m_class_get_byval_arg (klass)))
959 return NULL;
961 if (mono_field_get_flags (field) & FIELD_ATTRIBUTE_LITERAL) {
962 char *type_name = mono_type_get_full_name (field->parent);
963 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot reference literal field %s::%s at 0x%04x", type_name, field->name, ctx->ip_offset));
964 g_free (type_name);
965 return NULL;
968 *out_klass = klass;
969 return field;
972 static MonoMethod*
973 verifier_load_method (VerifyContext *ctx, int token, const char *opcode) {
974 MonoMethod* method;
977 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
978 method = (MonoMethod *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
979 } else {
980 ERROR_DECL (error);
981 if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
982 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);
983 return NULL;
986 method = mono_get_method_checked (ctx->image, token, NULL, ctx->generic_context, error);
987 mono_error_cleanup (error); /* FIXME don't swallow this error */
990 if (!method) {
991 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);
992 return NULL;
995 if (mono_method_is_valid_in_context (ctx, method) == RESULT_INVALID)
996 return NULL;
998 return method;
1001 static MonoType*
1002 verifier_load_type (VerifyContext *ctx, int token, const char *opcode) {
1003 MonoType* type;
1005 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
1006 MonoClass *klass = (MonoClass *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
1007 type = klass ? m_class_get_byval_arg (klass) : NULL;
1008 } else {
1009 ERROR_DECL (error);
1010 if (!IS_TYPE_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
1011 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid type token 0x%08x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
1012 return NULL;
1014 type = mono_type_get_checked (ctx->image, token, ctx->generic_context, error);
1015 mono_error_cleanup (error); /*FIXME don't swallow the error */
1018 if (!type) {
1019 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);
1020 return NULL;
1023 if (!mono_type_is_valid_in_context (ctx, type))
1024 return NULL;
1026 return type;
1030 /* stack_slot_get_type:
1032 * Returns the stack type of @value. This value includes POINTER_MASK.
1034 * Use this function to checks that account for a managed pointer.
1036 static gint32
1037 stack_slot_get_type (ILStackDesc *value)
1039 return value->stype & RAW_TYPE_MASK;
1042 /* stack_slot_get_underlying_type:
1044 * Returns the stack type of @value. This value does not include POINTER_MASK.
1046 * Use this function is cases where the fact that the value could be a managed pointer is
1047 * irrelevant. For example, field load doesn't care about this fact of type on stack.
1049 static gint32
1050 stack_slot_get_underlying_type (ILStackDesc *value)
1052 return value->stype & TYPE_MASK;
1055 /* stack_slot_is_managed_pointer:
1057 * Returns TRUE is @value is a managed pointer.
1059 static gboolean
1060 stack_slot_is_managed_pointer (ILStackDesc *value)
1062 return (value->stype & POINTER_MASK) == POINTER_MASK;
1065 /* stack_slot_is_managed_mutability_pointer:
1067 * Returns TRUE is @value is a managed mutability pointer.
1069 static G_GNUC_UNUSED gboolean
1070 stack_slot_is_managed_mutability_pointer (ILStackDesc *value)
1072 return (value->stype & CMMP_MASK) == CMMP_MASK;
1075 /* stack_slot_is_null_literal:
1077 * Returns TRUE is @value is the null literal.
1079 static gboolean
1080 stack_slot_is_null_literal (ILStackDesc *value)
1082 return (value->stype & NULL_LITERAL_MASK) == NULL_LITERAL_MASK;
1086 /* stack_slot_is_this_pointer:
1088 * Returns TRUE is @value is the this literal
1090 static gboolean
1091 stack_slot_is_this_pointer (ILStackDesc *value)
1093 return (value->stype & THIS_POINTER_MASK) == THIS_POINTER_MASK;
1096 /* stack_slot_is_boxed_value:
1098 * Returns TRUE is @value is a boxed value
1100 static gboolean
1101 stack_slot_is_boxed_value (ILStackDesc *value)
1103 return (value->stype & BOXED_MASK) == BOXED_MASK;
1106 /* stack_slot_is_safe_byref:
1108 * Returns TRUE is @value is a safe byref
1110 static gboolean
1111 stack_slot_is_safe_byref (ILStackDesc *value)
1113 return (value->stype & SAFE_BYREF_MASK) == SAFE_BYREF_MASK;
1116 static const char *
1117 stack_slot_get_name (ILStackDesc *value)
1119 return type_names [value->stype & TYPE_MASK];
1122 enum {
1123 SAFE_BYREF_LOCAL = 1,
1124 UNSAFE_BYREF_LOCAL = 2
1126 static gboolean
1127 local_is_safe_byref (VerifyContext *ctx, unsigned int arg)
1129 return ctx->locals_verification_state [arg] == SAFE_BYREF_LOCAL;
1132 static gboolean
1133 local_is_unsafe_byref (VerifyContext *ctx, unsigned int arg)
1135 return ctx->locals_verification_state [arg] == UNSAFE_BYREF_LOCAL;
1138 #define APPEND_WITH_PREDICATE(PRED,NAME) do {\
1139 if (PRED (value)) { \
1140 if (!first) \
1141 g_string_append (str, ", "); \
1142 g_string_append (str, NAME); \
1143 first = FALSE; \
1144 } } while (0)
1146 static char*
1147 stack_slot_stack_type_full_name (ILStackDesc *value)
1149 GString *str = g_string_new ("");
1150 char *result;
1151 gboolean has_pred = FALSE, first = TRUE;
1153 if ((value->stype & TYPE_MASK) != value->stype) {
1154 g_string_append(str, "[");
1155 APPEND_WITH_PREDICATE (stack_slot_is_this_pointer, "this");
1156 APPEND_WITH_PREDICATE (stack_slot_is_boxed_value, "boxed");
1157 APPEND_WITH_PREDICATE (stack_slot_is_null_literal, "null");
1158 APPEND_WITH_PREDICATE (stack_slot_is_managed_mutability_pointer, "cmmp");
1159 APPEND_WITH_PREDICATE (stack_slot_is_managed_pointer, "mp");
1160 APPEND_WITH_PREDICATE (stack_slot_is_safe_byref, "safe-byref");
1161 has_pred = TRUE;
1164 if (mono_type_is_generic_argument (value->type) && !stack_slot_is_boxed_value (value)) {
1165 if (!has_pred)
1166 g_string_append(str, "[");
1167 if (!first)
1168 g_string_append (str, ", ");
1169 g_string_append (str, "unboxed");
1170 has_pred = TRUE;
1173 if (has_pred)
1174 g_string_append(str, "] ");
1176 g_string_append (str, stack_slot_get_name (value));
1177 result = str->str;
1178 g_string_free (str, FALSE);
1179 return result;
1182 static char*
1183 stack_slot_full_name (ILStackDesc *value)
1185 char *type_name = mono_type_full_name (value->type);
1186 char *stack_name = stack_slot_stack_type_full_name (value);
1187 char *res = g_strdup_printf ("%s (%s)", type_name, stack_name);
1188 g_free (type_name);
1189 g_free (stack_name);
1190 return res;
1193 //////////////////////////////////////////////////////////////////
1196 * mono_free_verify_list:
1198 void
1199 mono_free_verify_list (GSList *list)
1201 MonoVerifyInfoExtended *info;
1202 GSList *tmp;
1204 for (tmp = list; tmp; tmp = tmp->next) {
1205 info = (MonoVerifyInfoExtended *)tmp->data;
1206 g_free (info->info.message);
1207 g_free (info);
1209 g_slist_free (list);
1212 #define ADD_ERROR(list,msg) \
1213 do { \
1214 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1215 vinfo->info.status = MONO_VERIFY_ERROR; \
1216 vinfo->info.message = (msg); \
1217 (list) = g_slist_prepend ((list), vinfo); \
1218 } while (0)
1220 #define ADD_WARN(list,code,msg) \
1221 do { \
1222 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1223 vinfo->info.status = (code); \
1224 vinfo->info.message = (msg); \
1225 (list) = g_slist_prepend ((list), vinfo); \
1226 } while (0)
1228 #define ADD_INVALID(list,msg) \
1229 do { \
1230 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1231 vinfo->status = MONO_VERIFY_ERROR; \
1232 vinfo->message = (msg); \
1233 (list) = g_slist_prepend ((list), vinfo); \
1234 /*G_BREAKPOINT ();*/ \
1235 goto invalid_cil; \
1236 } while (0)
1238 #define CHECK_STACK_UNDERFLOW(num) \
1239 do { \
1240 if (cur_stack < (num)) \
1241 ADD_INVALID (list, g_strdup_printf ("Stack underflow at 0x%04x (%d items instead of %d)", ip_offset, cur_stack, (num))); \
1242 } while (0)
1244 #define CHECK_STACK_OVERFLOW() \
1245 do { \
1246 if (cur_stack >= max_stack) \
1247 ADD_INVALID (list, g_strdup_printf ("Maxstack exceeded at 0x%04x", ip_offset)); \
1248 } while (0)
1251 static int
1252 in_any_block (MonoMethodHeader *header, guint offset)
1254 int i;
1255 MonoExceptionClause *clause;
1257 for (i = 0; i < header->num_clauses; ++i) {
1258 clause = &header->clauses [i];
1259 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1260 return 1;
1261 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1262 return 1;
1263 if (MONO_OFFSET_IN_FILTER (clause, offset))
1264 return 1;
1266 return 0;
1270 * in_any_exception_block:
1272 * Returns TRUE is @offset is part of any exception clause (filter, handler, catch, finally or fault).
1274 static gboolean
1275 in_any_exception_block (MonoMethodHeader *header, guint offset)
1277 int i;
1278 MonoExceptionClause *clause;
1280 for (i = 0; i < header->num_clauses; ++i) {
1281 clause = &header->clauses [i];
1282 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1283 return TRUE;
1284 if (MONO_OFFSET_IN_FILTER (clause, offset))
1285 return TRUE;
1287 return FALSE;
1291 * is_valid_branch_instruction:
1293 * Verify if it's valid to perform a branch from @offset to @target.
1294 * This should be used with br and brtrue/false.
1295 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1296 * The major difference from other similiar functions is that branching into a
1297 * finally/fault block is invalid instead of just unverifiable.
1299 static int
1300 is_valid_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1302 int i;
1303 MonoExceptionClause *clause;
1305 for (i = 0; i < header->num_clauses; ++i) {
1306 clause = &header->clauses [i];
1307 /*branching into a finally block is invalid*/
1308 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) &&
1309 !MONO_OFFSET_IN_HANDLER (clause, offset) &&
1310 MONO_OFFSET_IN_HANDLER (clause, target))
1311 return 2;
1313 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1314 return 1;
1315 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1316 return 1;
1317 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1318 return 1;
1320 return 0;
1324 * is_valid_cmp_branch_instruction:
1326 * Verify if it's valid to perform a branch from @offset to @target.
1327 * This should be used with binary comparison branching instruction, like beq, bge and similars.
1328 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1330 * The major differences from other similar functions are that most errors lead to invalid
1331 * code and only branching out of finally, filter or fault clauses is unverifiable.
1333 static int
1334 is_valid_cmp_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1336 int i;
1337 MonoExceptionClause *clause;
1339 for (i = 0; i < header->num_clauses; ++i) {
1340 clause = &header->clauses [i];
1341 /*branching out of a handler or finally*/
1342 if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE &&
1343 MONO_OFFSET_IN_HANDLER (clause, offset) &&
1344 !MONO_OFFSET_IN_HANDLER (clause, target))
1345 return 1;
1347 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1348 return 2;
1349 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1350 return 2;
1351 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1352 return 2;
1354 return 0;
1358 * A leave can't escape a finally block
1360 static int
1361 is_correct_leave (MonoMethodHeader *header, guint offset, guint target)
1363 int i;
1364 MonoExceptionClause *clause;
1366 for (i = 0; i < header->num_clauses; ++i) {
1367 clause = &header->clauses [i];
1368 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY && MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
1369 return 0;
1370 if (MONO_OFFSET_IN_FILTER (clause, offset))
1371 return 0;
1373 return 1;
1377 * A rethrow can't happen outside of a catch handler.
1379 static int
1380 is_correct_rethrow (MonoMethodHeader *header, guint offset)
1382 int i;
1383 MonoExceptionClause *clause;
1385 for (i = 0; i < header->num_clauses; ++i) {
1386 clause = &header->clauses [i];
1387 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1388 return 1;
1390 return 0;
1394 * An endfinally can't happen outside of a finally/fault handler.
1396 static int
1397 is_correct_endfinally (MonoMethodHeader *header, guint offset)
1399 int i;
1400 MonoExceptionClause *clause;
1402 for (i = 0; i < header->num_clauses; ++i) {
1403 clause = &header->clauses [i];
1404 if (MONO_OFFSET_IN_HANDLER (clause, offset) && (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY))
1405 return 1;
1407 return 0;
1412 * An endfilter can only happens inside a filter clause.
1413 * In non-strict mode filter is allowed inside the handler clause too
1415 static MonoExceptionClause *
1416 is_correct_endfilter (VerifyContext *ctx, guint offset)
1418 int i;
1419 MonoExceptionClause *clause;
1421 for (i = 0; i < ctx->header->num_clauses; ++i) {
1422 clause = &ctx->header->clauses [i];
1423 if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER)
1424 continue;
1425 if (MONO_OFFSET_IN_FILTER (clause, offset))
1426 return clause;
1427 if (!IS_STRICT_MODE (ctx) && MONO_OFFSET_IN_HANDLER (clause, offset))
1428 return clause;
1430 return NULL;
1435 * Non-strict endfilter can happens inside a try block or any handler block
1437 static int
1438 is_unverifiable_endfilter (VerifyContext *ctx, guint offset)
1440 int i;
1441 MonoExceptionClause *clause;
1443 for (i = 0; i < ctx->header->num_clauses; ++i) {
1444 clause = &ctx->header->clauses [i];
1445 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1446 return 1;
1448 return 0;
1451 static gboolean
1452 is_valid_bool_arg (ILStackDesc *arg)
1454 if (stack_slot_is_managed_pointer (arg) || stack_slot_is_boxed_value (arg) || stack_slot_is_null_literal (arg))
1455 return TRUE;
1458 switch (stack_slot_get_underlying_type (arg)) {
1459 case TYPE_I4:
1460 case TYPE_I8:
1461 case TYPE_NATIVE_INT:
1462 case TYPE_PTR:
1463 return TRUE;
1464 case TYPE_COMPLEX:
1465 g_assert (arg->type);
1466 switch (arg->type->type) {
1467 case MONO_TYPE_CLASS:
1468 case MONO_TYPE_STRING:
1469 case MONO_TYPE_OBJECT:
1470 case MONO_TYPE_SZARRAY:
1471 case MONO_TYPE_ARRAY:
1472 case MONO_TYPE_FNPTR:
1473 case MONO_TYPE_PTR:
1474 return TRUE;
1475 case MONO_TYPE_GENERICINST:
1476 /*We need to check if the container class
1477 * of the generic type is a valuetype, iow:
1478 * is it a "class Foo<T>" or a "struct Foo<T>"?
1480 return !m_class_is_valuetype (arg->type->data.generic_class->container_class);
1481 default:
1482 return FALSE;
1484 default:
1485 return FALSE;
1490 /*Type manipulation helper*/
1492 /*Returns the byref version of the supplied MonoType*/
1493 static MonoType*
1494 mono_type_get_type_byref (MonoType *type)
1496 if (type->byref)
1497 return type;
1498 return m_class_get_this_arg (mono_class_from_mono_type (type));
1502 /*Returns the byval version of the supplied MonoType*/
1503 static MonoType*
1504 mono_type_get_type_byval (MonoType *type)
1506 if (!type->byref)
1507 return type;
1508 return m_class_get_byval_arg (mono_class_from_mono_type (type));
1511 static MonoType*
1512 mono_type_from_stack_slot (ILStackDesc *slot)
1514 if (stack_slot_is_managed_pointer (slot))
1515 return mono_type_get_type_byref (slot->type);
1516 return slot->type;
1519 /*Stack manipulation code*/
1521 static void
1522 ensure_stack_size (ILCodeDesc *stack, int required)
1524 int new_size = 8;
1525 ILStackDesc *tmp;
1527 if (required < stack->max_size)
1528 return;
1530 /* We don't have to worry about the exponential growth since stack_copy prune unused space */
1531 new_size = MAX (8, MAX (required, stack->max_size * 2));
1533 g_assert (new_size >= stack->size);
1534 g_assert (new_size >= required);
1536 tmp = g_new0 (ILStackDesc, new_size);
1537 _MEM_ALLOC (sizeof (ILStackDesc) * new_size);
1539 if (stack->stack) {
1540 if (stack->size)
1541 memcpy (tmp, stack->stack, stack->size * sizeof (ILStackDesc));
1542 g_free (stack->stack);
1543 _MEM_FREE (sizeof (ILStackDesc) * stack->max_size);
1546 stack->stack = tmp;
1547 stack->max_size = new_size;
1550 static void
1551 stack_init (VerifyContext *ctx, ILCodeDesc *state)
1553 if (state->flags & IL_CODE_FLAG_STACK_INITED)
1554 return;
1555 state->size = state->max_size = 0;
1556 state->flags |= IL_CODE_FLAG_STACK_INITED;
1559 static void
1560 stack_copy (ILCodeDesc *to, ILCodeDesc *from)
1562 ensure_stack_size (to, from->size);
1563 to->size = from->size;
1565 /*stack copy happens at merge points, which have small stacks*/
1566 if (from->size)
1567 memcpy (to->stack, from->stack, sizeof (ILStackDesc) * from->size);
1570 static void
1571 copy_stack_value (ILStackDesc *to, ILStackDesc *from)
1573 to->stype = from->stype;
1574 to->type = from->type;
1575 to->method = from->method;
1578 static int
1579 check_underflow (VerifyContext *ctx, int size)
1581 if (ctx->eval.size < size) {
1582 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack underflow, required %d, but have %d at 0x%04x", size, ctx->eval.size, ctx->ip_offset));
1583 return 0;
1585 return 1;
1588 static int
1589 check_overflow (VerifyContext *ctx)
1591 if (ctx->eval.size >= ctx->max_stack) {
1592 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have stack-depth %d at 0x%04x", ctx->eval.size + 1, ctx->ip_offset));
1593 return 0;
1595 return 1;
1598 /*This reject out PTR, FNPTR and TYPEDBYREF*/
1599 static gboolean
1600 check_unmanaged_pointer (VerifyContext *ctx, ILStackDesc *value)
1602 if (stack_slot_get_type (value) == TYPE_PTR) {
1603 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1604 return 0;
1606 return 1;
1609 /*TODO verify if MONO_TYPE_TYPEDBYREF is not allowed here as well.*/
1610 static gboolean
1611 check_unverifiable_type (VerifyContext *ctx, MonoType *type)
1613 if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
1614 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1615 return 0;
1617 return 1;
1620 static ILStackDesc *
1621 stack_push (VerifyContext *ctx)
1623 g_assert (ctx->eval.size < ctx->max_stack);
1624 g_assert (ctx->eval.size <= ctx->eval.max_size);
1626 ensure_stack_size (&ctx->eval, ctx->eval.size + 1);
1628 return & ctx->eval.stack [ctx->eval.size++];
1631 static ILStackDesc *
1632 stack_push_val (VerifyContext *ctx, int stype, MonoType *type)
1634 ILStackDesc *top = stack_push (ctx);
1635 top->stype = stype;
1636 top->type = type;
1637 return top;
1640 static ILStackDesc *
1641 stack_pop (VerifyContext *ctx)
1643 ILStackDesc *ret;
1644 g_assert (ctx->eval.size > 0);
1645 ret = ctx->eval.stack + --ctx->eval.size;
1646 if ((ret->stype & UNINIT_THIS_MASK) == UNINIT_THIS_MASK)
1647 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Found use of uninitialized 'this ptr' ref at 0x%04x", ctx->ip_offset));
1648 return ret;
1651 /* This function allows to safely pop an unititialized this ptr from
1652 * the eval stack without marking the method as unverifiable.
1654 static ILStackDesc *
1655 stack_pop_safe (VerifyContext *ctx)
1657 g_assert (ctx->eval.size > 0);
1658 return ctx->eval.stack + --ctx->eval.size;
1661 /*Positive number distance from stack top. [0] is stack top, [1] is the one below*/
1662 static ILStackDesc*
1663 stack_peek (VerifyContext *ctx, int distance)
1665 g_assert (ctx->eval.size - distance > 0);
1666 return ctx->eval.stack + (ctx->eval.size - 1 - distance);
1669 static ILStackDesc *
1670 stack_push_stack_val (VerifyContext *ctx, ILStackDesc *value)
1672 ILStackDesc *top = stack_push (ctx);
1673 copy_stack_value (top, value);
1674 return top;
1677 /* Returns the MonoType associated with the token, or NULL if it is invalid.
1679 * A boxable type can be either a reference or value type, but cannot be a byref type or an unmanaged pointer
1680 * */
1681 static MonoType*
1682 get_boxable_mono_type (VerifyContext* ctx, int token, const char *opcode)
1684 MonoType *type;
1685 MonoClass *klass;
1687 if (!(type = verifier_load_type (ctx, token, opcode)))
1688 return NULL;
1690 if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
1691 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type for %s at 0x%04x", opcode, ctx->ip_offset));
1692 return NULL;
1695 if (type->type == MONO_TYPE_VOID) {
1696 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type for %s at 0x%04x", opcode, ctx->ip_offset));
1697 return NULL;
1700 if (type->type == MONO_TYPE_TYPEDBYREF)
1701 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid use of typedbyref for %s at 0x%04x", opcode, ctx->ip_offset));
1703 if (!(klass = mono_class_from_mono_type (type)))
1704 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not retrieve type token for %s at 0x%04x", opcode, ctx->ip_offset));
1706 if (mono_class_is_gtd (klass) && type->type != MONO_TYPE_GENERICINST)
1707 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));
1709 check_unverifiable_type (ctx, type);
1710 return type;
1714 /*operation result tables */
1716 static const unsigned char bin_op_table [TYPE_MAX][TYPE_MAX] = {
1717 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1718 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1719 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1720 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1721 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1722 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1725 static const unsigned char add_table [TYPE_MAX][TYPE_MAX] = {
1726 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1727 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1728 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1729 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1730 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1731 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1734 static const unsigned char sub_table [TYPE_MAX][TYPE_MAX] = {
1735 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1736 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1737 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1738 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1739 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1740 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1743 static const unsigned char int_bin_op_table [TYPE_MAX][TYPE_MAX] = {
1744 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1745 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1746 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1747 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1748 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1749 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1752 static const unsigned char shift_op_table [TYPE_MAX][TYPE_MAX] = {
1753 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1754 {TYPE_I8, TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV},
1755 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1756 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1757 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1758 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1761 static const unsigned char cmp_br_op [TYPE_MAX][TYPE_MAX] = {
1762 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1763 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1764 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1765 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1766 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV},
1767 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1770 static const unsigned char cmp_br_eq_op [TYPE_MAX][TYPE_MAX] = {
1771 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1772 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1773 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV},
1774 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1775 {TYPE_INV, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_I4, TYPE_INV},
1776 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4},
1779 static const unsigned char add_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
1780 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1781 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1782 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1783 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1784 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1785 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1788 static const unsigned char sub_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
1789 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1790 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1791 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1792 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1793 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1794 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1797 static const unsigned char bin_ovf_table [TYPE_MAX][TYPE_MAX] = {
1798 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1799 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1800 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1801 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1802 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1803 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1806 #ifdef MONO_VERIFIER_DEBUG
1808 /*debug helpers */
1809 static void
1810 dump_stack_value (ILStackDesc *value)
1812 printf ("[(%x)(%x)", value->type->type, value->stype);
1814 if (stack_slot_is_this_pointer (value))
1815 printf ("[this] ");
1817 if (stack_slot_is_boxed_value (value))
1818 printf ("[boxed] ");
1820 if (stack_slot_is_null_literal (value))
1821 printf ("[null] ");
1823 if (stack_slot_is_managed_mutability_pointer (value))
1824 printf ("Controled Mutability MP: ");
1826 if (stack_slot_is_managed_pointer (value))
1827 printf ("Managed Pointer to: ");
1829 if (stack_slot_is_safe_byref (value))
1830 printf ("Safe ByRef to: ");
1832 switch (stack_slot_get_underlying_type (value)) {
1833 case TYPE_INV:
1834 printf ("invalid type]");
1835 return;
1836 case TYPE_I4:
1837 printf ("int32]");
1838 return;
1839 case TYPE_I8:
1840 printf ("int64]");
1841 return;
1842 case TYPE_NATIVE_INT:
1843 printf ("native int]");
1844 return;
1845 case TYPE_R8:
1846 printf ("float64]");
1847 return;
1848 case TYPE_PTR:
1849 printf ("unmanaged pointer]");
1850 return;
1851 case TYPE_COMPLEX:
1852 switch (value->type->type) {
1853 case MONO_TYPE_CLASS:
1854 case MONO_TYPE_VALUETYPE:
1855 printf ("complex] (%s)", value->type->data.klass->name);
1856 return;
1857 case MONO_TYPE_STRING:
1858 printf ("complex] (string)");
1859 return;
1860 case MONO_TYPE_OBJECT:
1861 printf ("complex] (object)");
1862 return;
1863 case MONO_TYPE_SZARRAY:
1864 printf ("complex] (%s [])", value->type->data.klass->name);
1865 return;
1866 case MONO_TYPE_ARRAY:
1867 printf ("complex] (%s [%d %d %d])",
1868 value->type->data.array->eklass->name,
1869 value->type->data.array->rank,
1870 value->type->data.array->numsizes,
1871 value->type->data.array->numlobounds);
1872 return;
1873 case MONO_TYPE_GENERICINST:
1874 printf ("complex] (inst of %s )", value->type->data.generic_class->container_class->name);
1875 return;
1876 case MONO_TYPE_VAR:
1877 printf ("complex] (type generic param !%d - %s) ", value->type->data.generic_param->num, mono_generic_param_name (value->type->data.generic_param));
1878 return;
1879 case MONO_TYPE_MVAR:
1880 printf ("complex] (method generic param !!%d - %s) ", value->type->data.generic_param->num, mono_generic_param_name (value->type->data.generic_param));
1881 return;
1882 default: {
1883 //should be a boxed value
1884 char * name = mono_type_full_name (value->type);
1885 printf ("complex] %s", name);
1886 g_free (name);
1887 return;
1890 default:
1891 printf ("unknown stack %x type]\n", value->stype);
1892 g_assert_not_reached ();
1896 static void
1897 dump_stack_state (ILCodeDesc *state)
1899 int i;
1901 printf ("(%d) ", state->size);
1902 for (i = 0; i < state->size; ++i)
1903 dump_stack_value (state->stack + i);
1904 printf ("\n");
1906 #endif
1909 * is_array_type_compatible:
1911 * Returns TRUE if candidate array type can be assigned to target.
1913 * Both parameters MUST be of type MONO_TYPE_ARRAY (target->type == MONO_TYPE_ARRAY)
1915 static gboolean
1916 is_array_type_compatible (MonoType *target, MonoType *candidate)
1918 MonoArrayType *left = target->data.array;
1919 MonoArrayType *right = candidate->data.array;
1921 g_assert (target->type == MONO_TYPE_ARRAY);
1922 g_assert (candidate->type == MONO_TYPE_ARRAY);
1924 if (left->rank != right->rank)
1925 return FALSE;
1927 return verifier_class_is_assignable_from (left->eklass, right->eklass);
1930 static int
1931 get_stack_type (MonoType *type)
1933 int mask = 0;
1934 int type_kind = type->type;
1935 if (type->byref)
1936 mask = POINTER_MASK;
1937 /*TODO handle CMMP_MASK */
1939 handle_enum:
1940 switch (type_kind) {
1941 case MONO_TYPE_I1:
1942 case MONO_TYPE_U1:
1943 case MONO_TYPE_BOOLEAN:
1944 case MONO_TYPE_I2:
1945 case MONO_TYPE_U2:
1946 case MONO_TYPE_CHAR:
1947 case MONO_TYPE_I4:
1948 case MONO_TYPE_U4:
1949 return TYPE_I4 | mask;
1951 case MONO_TYPE_I:
1952 case MONO_TYPE_U:
1953 return TYPE_NATIVE_INT | mask;
1955 /* FIXME: the spec says that you cannot have a pointer to method pointer, do we need to check this here? */
1956 case MONO_TYPE_FNPTR:
1957 case MONO_TYPE_PTR:
1958 case MONO_TYPE_TYPEDBYREF:
1959 return TYPE_PTR | mask;
1961 case MONO_TYPE_VAR:
1962 case MONO_TYPE_MVAR:
1964 case MONO_TYPE_CLASS:
1965 case MONO_TYPE_STRING:
1966 case MONO_TYPE_OBJECT:
1967 case MONO_TYPE_SZARRAY:
1968 case MONO_TYPE_ARRAY:
1969 return TYPE_COMPLEX | mask;
1971 case MONO_TYPE_I8:
1972 case MONO_TYPE_U8:
1973 return TYPE_I8 | mask;
1975 case MONO_TYPE_R4:
1976 case MONO_TYPE_R8:
1977 return TYPE_R8 | mask;
1979 case MONO_TYPE_GENERICINST:
1980 case MONO_TYPE_VALUETYPE:
1981 if (mono_type_is_enum_type (type)) {
1982 type = mono_type_get_underlying_type_any (type);
1983 if (!type)
1984 return FALSE;
1985 type_kind = type->type;
1986 goto handle_enum;
1987 } else {
1988 return TYPE_COMPLEX | mask;
1991 default:
1992 return TYPE_INV;
1996 /* convert MonoType to ILStackDesc format (stype) */
1997 static gboolean
1998 set_stack_value (VerifyContext *ctx, ILStackDesc *stack, MonoType *type, int take_addr)
2000 int mask = 0;
2001 int type_kind = type->type;
2003 if (type->byref || take_addr)
2004 mask = POINTER_MASK;
2005 /* TODO handle CMMP_MASK */
2007 handle_enum:
2008 stack->type = type;
2010 switch (type_kind) {
2011 case MONO_TYPE_I1:
2012 case MONO_TYPE_U1:
2013 case MONO_TYPE_BOOLEAN:
2014 case MONO_TYPE_I2:
2015 case MONO_TYPE_U2:
2016 case MONO_TYPE_CHAR:
2017 case MONO_TYPE_I4:
2018 case MONO_TYPE_U4:
2019 stack->stype = TYPE_I4 | mask;
2020 break;
2021 case MONO_TYPE_I:
2022 case MONO_TYPE_U:
2023 stack->stype = TYPE_NATIVE_INT | mask;
2024 break;
2026 /*FIXME: Do we need to check if it's a pointer to the method pointer? The spec says it' illegal to have that.*/
2027 case MONO_TYPE_FNPTR:
2028 case MONO_TYPE_PTR:
2029 case MONO_TYPE_TYPEDBYREF:
2030 stack->stype = TYPE_PTR | mask;
2031 break;
2033 case MONO_TYPE_CLASS:
2034 case MONO_TYPE_STRING:
2035 case MONO_TYPE_OBJECT:
2036 case MONO_TYPE_SZARRAY:
2037 case MONO_TYPE_ARRAY:
2039 case MONO_TYPE_VAR:
2040 case MONO_TYPE_MVAR:
2041 stack->stype = TYPE_COMPLEX | mask;
2042 break;
2044 case MONO_TYPE_I8:
2045 case MONO_TYPE_U8:
2046 stack->stype = TYPE_I8 | mask;
2047 break;
2048 case MONO_TYPE_R4:
2049 case MONO_TYPE_R8:
2050 stack->stype = TYPE_R8 | mask;
2051 break;
2052 case MONO_TYPE_GENERICINST:
2053 case MONO_TYPE_VALUETYPE:
2054 if (mono_type_is_enum_type (type)) {
2055 MonoType *utype = mono_type_get_underlying_type_any (type);
2056 if (!utype) {
2057 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not resolve underlying type of %x at %d", type->type, ctx->ip_offset));
2058 return FALSE;
2060 type = utype;
2061 type_kind = type->type;
2062 goto handle_enum;
2063 } else {
2064 stack->stype = TYPE_COMPLEX | mask;
2065 break;
2067 default:
2068 VERIFIER_DEBUG ( printf ("unknown type 0x%02x in eval stack type\n", type->type); );
2069 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Illegal value set on stack 0x%02x at %d", type->type, ctx->ip_offset));
2070 return FALSE;
2072 return TRUE;
2076 * init_stack_with_value_at_exception_boundary:
2078 * Initialize the stack and push a given type.
2079 * The instruction is marked as been on the exception boundary.
2081 static void
2082 init_stack_with_value_at_exception_boundary (VerifyContext *ctx, ILCodeDesc *code, MonoClass *klass)
2084 ERROR_DECL (error);
2085 MonoType *type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (klass), ctx->generic_context, error);
2087 if (!mono_error_ok (error)) {
2088 char *name = mono_type_get_full_name (klass);
2089 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid class %s used for exception", name));
2090 g_free (name);
2091 mono_error_cleanup (error);
2092 return;
2095 if (!ctx->max_stack) {
2096 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack overflow at 0x%04x", ctx->ip_offset));
2097 return;
2100 stack_init (ctx, code);
2101 ensure_stack_size (code, 1);
2102 set_stack_value (ctx, code->stack, type, FALSE);
2103 ctx->exception_types = g_slist_prepend (ctx->exception_types, type);
2104 code->size = 1;
2105 code->flags |= IL_CODE_FLAG_WAS_TARGET;
2106 if (mono_type_is_generic_argument (type))
2107 code->stack->stype |= BOXED_MASK;
2109 /* Class lazy loading functions */
2110 static GENERATE_GET_CLASS_WITH_CACHE (ienumerable, "System.Collections.Generic", "IEnumerable`1")
2111 static GENERATE_GET_CLASS_WITH_CACHE (icollection, "System.Collections.Generic", "ICollection`1")
2112 static GENERATE_GET_CLASS_WITH_CACHE (ireadonly_list, "System.Collections.Generic", "IReadOnlyList`1")
2113 static GENERATE_GET_CLASS_WITH_CACHE (ireadonly_collection, "System.Collections.Generic", "IReadOnlyCollection`1")
2116 static MonoClass*
2117 get_ienumerable_class (void)
2119 return mono_class_get_ienumerable_class ();
2122 static MonoClass*
2123 get_icollection_class (void)
2125 return mono_class_get_icollection_class ();
2128 static MonoClass*
2129 get_ireadonlylist_class (void)
2131 return mono_class_get_ireadonly_list_class ();
2134 static MonoClass*
2135 get_ireadonlycollection_class (void)
2137 return mono_class_get_ireadonly_collection_class ();
2140 static MonoClass*
2141 inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
2143 MonoType *args [1];
2144 args [0] = m_class_get_byval_arg (arg0);
2146 return mono_class_bind_generic_parameters (gtype, 1, args, FALSE);
2149 static gboolean
2150 verifier_inflate_and_check_compat (MonoClass *target, MonoClass *gtd, MonoClass *arg)
2152 MonoClass *tmp;
2153 if (!(tmp = inflate_class_one_arg (gtd, arg)))
2154 return FALSE;
2155 if (mono_class_is_variant_compatible (target, tmp, TRUE))
2156 return TRUE;
2157 return FALSE;
2160 static gboolean
2161 verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate)
2163 MonoClass *iface_gtd;
2165 if (target == candidate)
2166 return TRUE;
2168 if (mono_class_has_variant_generic_params (target)) {
2169 if (MONO_CLASS_IS_INTERFACE (target)) {
2170 if (MONO_CLASS_IS_INTERFACE (candidate) && mono_class_is_variant_compatible (target, candidate, TRUE))
2171 return TRUE;
2173 if (m_class_get_rank (candidate) == 1) {
2174 MonoClass *candidate_element_class = m_class_get_element_class (candidate);
2175 if (verifier_inflate_and_check_compat (target, mono_defaults.generic_ilist_class, candidate_element_class))
2176 return TRUE;
2177 if (verifier_inflate_and_check_compat (target, get_icollection_class (), candidate_element_class))
2178 return TRUE;
2179 if (verifier_inflate_and_check_compat (target, get_ienumerable_class (), candidate_element_class))
2180 return TRUE;
2181 if (verifier_inflate_and_check_compat (target, get_ireadonlylist_class (), candidate_element_class))
2182 return TRUE;
2183 if (verifier_inflate_and_check_compat (target, get_ireadonlycollection_class (), candidate_element_class))
2184 return TRUE;
2185 } else {
2186 ERROR_DECL (error);
2187 int i;
2188 while (candidate && candidate != mono_defaults.object_class) {
2189 mono_class_setup_interfaces (candidate, error);
2190 if (!mono_error_ok (error)) {
2191 mono_error_cleanup (error);
2192 return FALSE;
2195 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
2196 guint16 candidate_interface_offsets_count = m_class_get_interface_offsets_count (candidate);
2197 MonoClass **candidate_interfaces_packed = m_class_get_interfaces_packed (candidate);
2198 for (i = 0; i < candidate_interface_offsets_count; ++i) {
2199 MonoClass *iface = candidate_interfaces_packed [i];
2200 if (mono_class_is_variant_compatible (target, iface, TRUE))
2201 return TRUE;
2204 guint16 candidate_interface_count = m_class_get_interface_count (candidate);
2205 MonoClass **candidate_interfaces = m_class_get_interfaces (candidate);
2206 for (i = 0; i < candidate_interface_count; ++i) {
2207 MonoClass *iface = candidate_interfaces [i];
2208 if (mono_class_is_variant_compatible (target, iface, TRUE))
2209 return TRUE;
2211 candidate = m_class_get_parent (candidate);
2214 } else if (m_class_is_delegate (target)) {
2215 if (mono_class_is_variant_compatible (target, candidate, TRUE))
2216 return TRUE;
2218 return FALSE;
2221 if (mono_class_is_assignable_from_internal (target, candidate))
2222 return TRUE;
2224 if (!MONO_CLASS_IS_INTERFACE (target) || !mono_class_is_ginst (target) || m_class_get_rank (candidate) != 1)
2225 return FALSE;
2227 iface_gtd = mono_class_get_generic_class (target)->container_class;
2228 if (iface_gtd != mono_defaults.generic_ilist_class && iface_gtd != get_icollection_class () && iface_gtd != get_ienumerable_class ())
2229 return FALSE;
2231 target = mono_class_from_mono_type (mono_class_get_generic_class (target)->context.class_inst->type_argv [0]);
2232 candidate = m_class_get_element_class (candidate);
2234 return TRUE;
2237 /*Verify if type 'candidate' can be stored in type 'target'.
2239 * If strict, check for the underlying type and not the verification stack types
2241 static gboolean
2242 verify_type_compatibility_full (VerifyContext *ctx, MonoType *target, MonoType *candidate, gboolean strict)
2244 #define IS_ONE_OF3(T, A, B, C) (T == A || T == B || T == C)
2245 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
2247 MonoType *original_candidate = candidate;
2248 VERIFIER_DEBUG ( printf ("checking type compatibility %s x %s strict %d\n", mono_type_full_name (target), mono_type_full_name (candidate), strict); );
2250 /*only one is byref */
2251 if (candidate->byref ^ target->byref) {
2252 /* converting from native int to byref*/
2253 if (get_stack_type (candidate) == TYPE_NATIVE_INT && target->byref) {
2254 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("using byref native int at 0x%04x", ctx->ip_offset));
2255 return TRUE;
2257 return FALSE;
2259 strict |= target->byref;
2260 /*From now on we don't care about byref anymore, so it's ok to discard it here*/
2261 candidate = mono_type_get_underlying_type_any (candidate);
2263 handle_enum:
2264 switch (target->type) {
2265 case MONO_TYPE_VOID:
2266 return candidate->type == MONO_TYPE_VOID;
2267 case MONO_TYPE_I1:
2268 case MONO_TYPE_U1:
2269 case MONO_TYPE_BOOLEAN:
2270 if (strict)
2271 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I1, MONO_TYPE_U1, MONO_TYPE_BOOLEAN);
2272 case MONO_TYPE_I2:
2273 case MONO_TYPE_U2:
2274 case MONO_TYPE_CHAR:
2275 if (strict)
2276 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I2, MONO_TYPE_U2, MONO_TYPE_CHAR);
2277 case MONO_TYPE_I4:
2278 case MONO_TYPE_U4: {
2279 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2280 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2281 if (strict)
2282 return is_native_int || is_int4;
2283 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2286 case MONO_TYPE_I8:
2287 case MONO_TYPE_U8:
2288 return IS_ONE_OF2 (candidate->type, MONO_TYPE_I8, MONO_TYPE_U8);
2290 case MONO_TYPE_R4:
2291 case MONO_TYPE_R8:
2292 if (strict)
2293 return candidate->type == target->type;
2294 return IS_ONE_OF2 (candidate->type, MONO_TYPE_R4, MONO_TYPE_R8);
2296 case MONO_TYPE_I:
2297 case MONO_TYPE_U: {
2298 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2299 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2300 if (strict)
2301 return is_native_int || is_int4;
2302 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2305 case MONO_TYPE_PTR:
2306 if (candidate->type != MONO_TYPE_PTR)
2307 return FALSE;
2308 /* check the underlying type */
2309 return verify_type_compatibility_full (ctx, target->data.type, candidate->data.type, TRUE);
2311 case MONO_TYPE_FNPTR: {
2312 MonoMethodSignature *left, *right;
2313 if (candidate->type != MONO_TYPE_FNPTR)
2314 return FALSE;
2316 left = mono_type_get_signature (target);
2317 right = mono_type_get_signature (candidate);
2318 return mono_metadata_signature_equal (left, right) && left->call_convention == right->call_convention;
2321 case MONO_TYPE_GENERICINST: {
2322 MonoClass *target_klass;
2323 MonoClass *candidate_klass;
2324 if (mono_type_is_enum_type (target)) {
2325 target = mono_type_get_underlying_type_any (target);
2326 if (!target)
2327 return FALSE;
2328 goto handle_enum;
2331 * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
2332 * to take boxing status into account.
2334 if (mono_type_is_generic_argument (original_candidate))
2335 return FALSE;
2337 target_klass = mono_class_from_mono_type (target);
2338 candidate_klass = mono_class_from_mono_type (candidate);
2339 if (mono_class_is_nullable (target_klass)) {
2340 if (!mono_class_is_nullable (candidate_klass))
2341 return FALSE;
2342 return target_klass == candidate_klass;
2344 return verifier_class_is_assignable_from (target_klass, candidate_klass);
2347 case MONO_TYPE_STRING:
2348 return candidate->type == MONO_TYPE_STRING;
2350 case MONO_TYPE_CLASS:
2352 * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
2353 * to take boxing status into account.
2355 if (mono_type_is_generic_argument (original_candidate))
2356 return FALSE;
2358 if (candidate->type == MONO_TYPE_VALUETYPE)
2359 return FALSE;
2361 /* If candidate is an enum it should return true for System.Enum and supertypes.
2362 * That's why here we use the original type and not the underlying type.
2364 return verifier_class_is_assignable_from (target->data.klass, mono_class_from_mono_type (original_candidate));
2366 case MONO_TYPE_OBJECT:
2367 return MONO_TYPE_IS_REFERENCE (candidate);
2369 case MONO_TYPE_SZARRAY: {
2370 MonoClass *left;
2371 MonoClass *right;
2372 if (candidate->type != MONO_TYPE_SZARRAY)
2373 return FALSE;
2375 left = mono_class_from_mono_type (target);
2376 right = mono_class_from_mono_type (candidate);
2378 return verifier_class_is_assignable_from (left, right);
2381 case MONO_TYPE_ARRAY:
2382 if (candidate->type != MONO_TYPE_ARRAY)
2383 return FALSE;
2384 return is_array_type_compatible (target, candidate);
2386 case MONO_TYPE_TYPEDBYREF:
2387 return candidate->type == MONO_TYPE_TYPEDBYREF;
2389 case MONO_TYPE_VALUETYPE: {
2390 MonoClass *target_klass;
2391 MonoClass *candidate_klass;
2393 if (candidate->type == MONO_TYPE_CLASS)
2394 return FALSE;
2396 target_klass = mono_class_from_mono_type (target);
2397 candidate_klass = mono_class_from_mono_type (candidate);
2398 if (target_klass == candidate_klass)
2399 return TRUE;
2400 if (mono_type_is_enum_type (target)) {
2401 target = mono_type_get_underlying_type_any (target);
2402 if (!target)
2403 return FALSE;
2404 goto handle_enum;
2406 return FALSE;
2409 case MONO_TYPE_VAR:
2410 if (candidate->type != MONO_TYPE_VAR)
2411 return FALSE;
2412 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2414 case MONO_TYPE_MVAR:
2415 if (candidate->type != MONO_TYPE_MVAR)
2416 return FALSE;
2417 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2419 default:
2420 VERIFIER_DEBUG ( printf ("unknown store type %d\n", target->type); );
2421 g_assert_not_reached ();
2422 return FALSE;
2424 return 1;
2425 #undef IS_ONE_OF3
2426 #undef IS_ONE_OF2
2429 static gboolean
2430 verify_type_compatibility (VerifyContext *ctx, MonoType *target, MonoType *candidate)
2432 return verify_type_compatibility_full (ctx, target, candidate, FALSE);
2436 * Returns the generic param bound to the context been verified.
2439 static MonoGenericParam*
2440 get_generic_param (VerifyContext *ctx, MonoType *param)
2442 guint16 param_num = mono_type_get_generic_param_num (param);
2443 if (param->type == MONO_TYPE_VAR) {
2444 if (!ctx->generic_context->class_inst || ctx->generic_context->class_inst->type_argc <= param_num) {
2445 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic type argument %d", param_num));
2446 return NULL;
2448 return ctx->generic_context->class_inst->type_argv [param_num]->data.generic_param;
2451 /*param must be a MVAR */
2452 if (!ctx->generic_context->method_inst || ctx->generic_context->method_inst->type_argc <= param_num) {
2453 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic method argument %d", param_num));
2454 return NULL;
2456 return ctx->generic_context->method_inst->type_argv [param_num]->data.generic_param;
2460 static gboolean
2461 recursive_boxed_constraint_type_check (VerifyContext *ctx, MonoType *type, MonoClass *constraint_class, int recursion_level)
2463 MonoType *constraint_type = m_class_get_byval_arg (constraint_class);
2464 if (recursion_level <= 0)
2465 return FALSE;
2467 if (verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (constraint_type), FALSE))
2468 return TRUE;
2470 if (mono_type_is_generic_argument (constraint_type)) {
2471 MonoGenericParam *param = get_generic_param (ctx, constraint_type);
2472 MonoClass **klass;
2473 if (!param)
2474 return FALSE;
2475 for (klass = mono_generic_param_info (param)->constraints; klass && *klass; ++klass) {
2476 if (recursive_boxed_constraint_type_check (ctx, type, *klass, recursion_level - 1))
2477 return TRUE;
2480 return FALSE;
2483 /**
2484 * is_compatible_boxed_valuetype:
2486 * Returns: TRUE if @candidate / @stack is a valid boxed valuetype.
2488 * @type The source type. It it tested to be of the proper type.
2489 * @candidate type of the boxed valuetype.
2490 * @stack stack slot of the boxed valuetype, separate from @candidade since one could be changed before calling this function
2491 * @strict if TRUE candidate must be boxed compatible to the target type
2494 static gboolean
2495 is_compatible_boxed_valuetype (VerifyContext *ctx, MonoType *type, MonoType *candidate, ILStackDesc *stack, gboolean strict)
2497 if (!stack_slot_is_boxed_value (stack))
2498 return FALSE;
2499 if (type->byref || candidate->byref)
2500 return FALSE;
2502 if (mono_type_is_generic_argument (candidate)) {
2503 MonoGenericParam *param = get_generic_param (ctx, candidate);
2504 MonoClass **klass;
2505 if (!param)
2506 return FALSE;
2508 for (klass = mono_generic_param_info (param)->constraints; klass && *klass; ++klass) {
2509 /*256 should be enough since there can't be more than 255 generic arguments.*/
2510 if (recursive_boxed_constraint_type_check (ctx, type, *klass, 256))
2511 return TRUE;
2515 if (mono_type_is_generic_argument (type))
2516 return FALSE;
2518 if (!strict)
2519 return TRUE;
2521 return MONO_TYPE_IS_REFERENCE (type) && verifier_class_is_assignable_from (mono_class_from_mono_type (type), mono_class_from_mono_type (candidate));
2524 static int
2525 verify_stack_type_compatibility_full (VerifyContext *ctx, MonoType *type, ILStackDesc *stack, gboolean drop_byref, gboolean valuetype_must_be_boxed)
2527 MonoType *candidate = mono_type_from_stack_slot (stack);
2528 if (MONO_TYPE_IS_REFERENCE (type) && !type->byref && stack_slot_is_null_literal (stack))
2529 return TRUE;
2531 if (is_compatible_boxed_valuetype (ctx, type, candidate, stack, TRUE))
2532 return TRUE;
2534 if (valuetype_must_be_boxed && !stack_slot_is_boxed_value (stack) && !MONO_TYPE_IS_REFERENCE (candidate))
2535 return FALSE;
2537 if (!valuetype_must_be_boxed && stack_slot_is_boxed_value (stack))
2538 return FALSE;
2540 if (drop_byref)
2541 return verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (candidate), FALSE);
2543 /* Handle how Roslyn emit fixed statements by encoding it as byref */
2544 if (type->byref && candidate->byref && (type->type == MONO_TYPE_I) && !mono_type_is_reference (candidate)) {
2545 if (!IS_STRICT_MODE (ctx))
2546 return TRUE;
2549 return verify_type_compatibility_full (ctx, type, candidate, FALSE);
2552 static int
2553 verify_stack_type_compatibility (VerifyContext *ctx, MonoType *type, ILStackDesc *stack)
2555 return verify_stack_type_compatibility_full (ctx, type, stack, FALSE, FALSE);
2558 static gboolean
2559 mono_delegate_type_equal (MonoType *target, MonoType *candidate)
2561 if (candidate->byref ^ target->byref)
2562 return FALSE;
2564 switch (target->type) {
2565 case MONO_TYPE_VOID:
2566 case MONO_TYPE_I1:
2567 case MONO_TYPE_U1:
2568 case MONO_TYPE_BOOLEAN:
2569 case MONO_TYPE_I2:
2570 case MONO_TYPE_U2:
2571 case MONO_TYPE_CHAR:
2572 case MONO_TYPE_I4:
2573 case MONO_TYPE_U4:
2574 case MONO_TYPE_I8:
2575 case MONO_TYPE_U8:
2576 case MONO_TYPE_R4:
2577 case MONO_TYPE_R8:
2578 case MONO_TYPE_I:
2579 case MONO_TYPE_U:
2580 case MONO_TYPE_STRING:
2581 case MONO_TYPE_TYPEDBYREF:
2582 return candidate->type == target->type;
2584 case MONO_TYPE_PTR:
2585 if (candidate->type != MONO_TYPE_PTR)
2586 return FALSE;
2587 return mono_delegate_type_equal (target->data.type, candidate->data.type);
2589 case MONO_TYPE_FNPTR:
2590 if (candidate->type != MONO_TYPE_FNPTR)
2591 return FALSE;
2592 return mono_delegate_signature_equal (mono_type_get_signature (target), mono_type_get_signature (candidate), FALSE);
2594 case MONO_TYPE_GENERICINST: {
2595 MonoClass *target_klass;
2596 MonoClass *candidate_klass;
2597 target_klass = mono_class_from_mono_type (target);
2598 candidate_klass = mono_class_from_mono_type (candidate);
2599 /*FIXME handle nullables and enum*/
2600 return verifier_class_is_assignable_from (target_klass, candidate_klass);
2602 case MONO_TYPE_OBJECT:
2603 return MONO_TYPE_IS_REFERENCE (candidate);
2605 case MONO_TYPE_CLASS:
2606 return verifier_class_is_assignable_from(target->data.klass, mono_class_from_mono_type (candidate));
2608 case MONO_TYPE_SZARRAY:
2609 if (candidate->type != MONO_TYPE_SZARRAY)
2610 return FALSE;
2611 return verifier_class_is_assignable_from (m_class_get_element_class (mono_class_from_mono_type (target)), m_class_get_element_class (mono_class_from_mono_type (candidate)));
2613 case MONO_TYPE_ARRAY:
2614 if (candidate->type != MONO_TYPE_ARRAY)
2615 return FALSE;
2616 return is_array_type_compatible (target, candidate);
2618 case MONO_TYPE_VALUETYPE:
2619 /*FIXME handle nullables and enum*/
2620 return mono_class_from_mono_type (candidate) == mono_class_from_mono_type (target);
2622 case MONO_TYPE_VAR:
2623 return candidate->type == MONO_TYPE_VAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2624 return FALSE;
2626 case MONO_TYPE_MVAR:
2627 return candidate->type == MONO_TYPE_MVAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2628 return FALSE;
2630 default:
2631 VERIFIER_DEBUG ( printf ("Unknown type %d. Implement me!\n", target->type); );
2632 g_assert_not_reached ();
2633 return FALSE;
2637 static gboolean
2638 mono_delegate_param_equal (MonoType *delegate, MonoType *method)
2640 if (mono_metadata_type_equal_full (delegate, method, TRUE))
2641 return TRUE;
2643 return mono_delegate_type_equal (method, delegate);
2646 static gboolean
2647 mono_delegate_ret_equal (MonoType *delegate, MonoType *method)
2649 if (mono_metadata_type_equal_full (delegate, method, TRUE))
2650 return TRUE;
2652 return mono_delegate_type_equal (delegate, method);
2656 * mono_delegate_signature_equal:
2658 * Compare two signatures in the way expected by delegates.
2660 * This function only exists due to the fact that it should ignore the 'has_this' part of the signature.
2662 * FIXME can this function be eliminated and proper metadata functionality be used?
2664 static gboolean
2665 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn)
2667 int i;
2668 int method_offset = is_static_ldftn ? 1 : 0;
2670 if (delegate_sig->param_count + method_offset != method_sig->param_count)
2671 return FALSE;
2673 if (delegate_sig->call_convention != method_sig->call_convention)
2674 return FALSE;
2676 for (i = 0; i < delegate_sig->param_count; i++) {
2677 MonoType *p1 = delegate_sig->params [i];
2678 MonoType *p2 = method_sig->params [i + method_offset];
2680 if (!mono_delegate_param_equal (p1, p2))
2681 return FALSE;
2684 if (!mono_delegate_ret_equal (delegate_sig->ret, method_sig->ret))
2685 return FALSE;
2687 return TRUE;
2690 gboolean
2691 mono_verifier_is_signature_compatible (MonoMethodSignature *target, MonoMethodSignature *candidate)
2693 return mono_delegate_signature_equal (target, candidate, FALSE);
2697 * verify_ldftn_delegate:
2699 * Verify properties of ldftn based delegates.
2701 static void
2702 verify_ldftn_delegate (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2704 MonoMethod *method = funptr->method;
2706 /*ldftn non-final virtuals only allowed if method is not static,
2707 * the object is a this arg (comes from a ldarg.0), and there is no starg.0.
2708 * This rules doesn't apply if the object on stack is a boxed valuetype.
2710 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !mono_class_is_sealed (method->klass) && !stack_slot_is_boxed_value (value)) {
2711 /*A stdarg 0 must not happen, we fail here only in fail fast mode to avoid double error reports*/
2712 if (IS_FAIL_FAST_MODE (ctx) && ctx->has_this_store)
2713 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at 0x%04x", ctx->ip_offset));
2715 /*current method must not be static*/
2716 if (ctx->method->flags & METHOD_ATTRIBUTE_STATIC)
2717 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function at 0x%04x", ctx->ip_offset));
2719 /*value is the this pointer, loaded using ldarg.0 */
2720 if (!stack_slot_is_this_pointer (value))
2721 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));
2723 ctx->code [ctx->ip_offset].flags |= IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL;
2728 * verify_delegate_compatibility:
2730 * Verify delegate creation sequence.
2733 static void
2734 verify_delegate_compatibility (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2736 #define IS_VALID_OPCODE(offset, opcode) (ip [ip_offset - offset] == opcode && (ctx->code [ip_offset - offset].flags & IL_CODE_FLAG_SEEN))
2737 #define IS_LOAD_FUN_PTR(kind) (IS_VALID_OPCODE (6, CEE_PREFIX1) && ip [ip_offset - 5] == kind)
2739 MonoMethod *invoke, *method;
2740 const guint8 *ip = ctx->header->code;
2741 guint32 ip_offset = ctx->ip_offset;
2742 gboolean is_static_ldftn = FALSE, is_first_arg_bound = FALSE;
2744 if (stack_slot_get_type (funptr) != TYPE_PTR || !funptr->method) {
2745 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid function pointer parameter for delegate constructor at 0x%04x", ctx->ip_offset));
2746 return;
2749 invoke = mono_get_delegate_invoke (delegate);
2750 method = funptr->method;
2752 if (!method || !mono_method_signature (method)) {
2753 char *name = mono_type_get_full_name (delegate);
2754 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid method on stack to create delegate %s construction at 0x%04x", name, ctx->ip_offset));
2755 g_free (name);
2756 return;
2759 if (!invoke || !mono_method_signature (invoke)) {
2760 char *name = mono_type_get_full_name (delegate);
2761 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Delegate type %s with bad Invoke method at 0x%04x", name, ctx->ip_offset));
2762 g_free (name);
2763 return;
2766 is_static_ldftn = (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) && method->flags & METHOD_ATTRIBUTE_STATIC;
2768 if (is_static_ldftn)
2769 is_first_arg_bound = mono_method_signature (invoke)->param_count + 1 == mono_method_signature (method)->param_count;
2771 if (!mono_delegate_signature_equal (mono_method_signature (invoke), mono_method_signature (method), is_first_arg_bound)) {
2772 char *fun_sig = mono_signature_get_desc (mono_method_signature (method), FALSE);
2773 char *invoke_sig = mono_signature_get_desc (mono_method_signature (invoke), FALSE);
2774 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));
2775 g_free (fun_sig);
2776 g_free (invoke_sig);
2780 * Delegate code sequences:
2781 * [-6] ldftn token
2782 * newobj ...
2785 * [-7] dup
2786 * [-6] ldvirtftn token
2787 * newobj ...
2789 * ldftn sequence:*/
2790 if (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) {
2791 verify_ldftn_delegate (ctx, delegate, value, funptr);
2792 } else if (ip_offset > 6 && IS_VALID_OPCODE (7, CEE_DUP) && IS_LOAD_FUN_PTR (CEE_LDVIRTFTN)) {
2793 ctx->code [ip_offset - 6].flags |= IL_CODE_DELEGATE_SEQUENCE;
2794 }else {
2795 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid code sequence for delegate creation at 0x%04x", ctx->ip_offset));
2797 ctx->code [ip_offset].flags |= IL_CODE_DELEGATE_SEQUENCE;
2799 //general tests
2800 if (is_first_arg_bound) {
2801 if (mono_method_signature (method)->param_count == 0 || !verify_stack_type_compatibility_full (ctx, mono_method_signature (method)->params [0], value, FALSE, TRUE))
2802 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2803 } else {
2804 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
2805 if (!stack_slot_is_null_literal (value))
2806 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Non-null this args used with static function for delegate creation at 0x%04x", ctx->ip_offset));
2807 } else {
2808 if (!verify_stack_type_compatibility_full (ctx, m_class_get_byval_arg (method->klass), value, FALSE, TRUE) && !stack_slot_is_null_literal (value))
2809 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2813 if (stack_slot_get_type (value) != TYPE_COMPLEX)
2814 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid first parameter for delegate creation at 0x%04x", ctx->ip_offset));
2816 #undef IS_VALID_OPCODE
2817 #undef IS_LOAD_FUN_PTR
2820 static gboolean
2821 is_this_arg_of_struct_instance_method (unsigned int arg, VerifyContext *ctx)
2823 if (arg != 0)
2824 return FALSE;
2825 if (ctx->method->flags & METHOD_ATTRIBUTE_STATIC)
2826 return FALSE;
2827 if (!m_class_is_valuetype (ctx->method->klass))
2828 return FALSE;
2829 return TRUE;
2832 /* implement the opcode checks*/
2833 static void
2834 push_arg (VerifyContext *ctx, unsigned int arg, int take_addr)
2836 ILStackDesc *top;
2838 if (arg >= ctx->max_args) {
2839 if (take_addr)
2840 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2841 else {
2842 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2843 if (check_overflow (ctx)) //FIXME: what sane value could we ever push?
2844 stack_push_val (ctx, TYPE_I4, mono_get_int32_type ());
2846 } else if (check_overflow (ctx)) {
2847 /*We must let the value be pushed, otherwise we would get an underflow error*/
2848 check_unverifiable_type (ctx, ctx->params [arg]);
2849 if (ctx->params [arg]->byref && take_addr)
2850 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2851 top = stack_push (ctx);
2852 if (!set_stack_value (ctx, top, ctx->params [arg], take_addr))
2853 return;
2855 if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC)) {
2856 if (take_addr)
2857 ctx->has_this_store = TRUE;
2858 else
2859 top->stype |= THIS_POINTER_MASK;
2860 if (mono_method_is_constructor (ctx->method) && !ctx->super_ctor_called && !m_class_is_valuetype (ctx->method->klass))
2861 top->stype |= UNINIT_THIS_MASK;
2863 if (!take_addr && ctx->params [arg]->byref && !is_this_arg_of_struct_instance_method (arg, ctx))
2864 top->stype |= SAFE_BYREF_MASK;
2868 static void
2869 push_local (VerifyContext *ctx, guint32 arg, int take_addr)
2871 if (arg >= ctx->num_locals) {
2872 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local %d", arg + 1));
2873 } else if (check_overflow (ctx)) {
2874 /*We must let the value be pushed, otherwise we would get an underflow error*/
2875 check_unverifiable_type (ctx, ctx->locals [arg]);
2876 if (ctx->locals [arg]->byref && take_addr)
2877 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2879 ILStackDesc *value = stack_push (ctx);
2880 set_stack_value (ctx, value, ctx->locals [arg], take_addr);
2881 if (local_is_safe_byref (ctx, arg))
2882 value->stype |= SAFE_BYREF_MASK;
2886 static void
2887 store_arg (VerifyContext *ctx, guint32 arg)
2889 ILStackDesc *value;
2891 if (arg >= ctx->max_args) {
2892 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", arg + 1, ctx->ip_offset));
2893 if (check_underflow (ctx, 1))
2894 stack_pop (ctx);
2895 return;
2898 if (check_underflow (ctx, 1)) {
2899 value = stack_pop (ctx);
2900 if (!verify_stack_type_compatibility (ctx, ctx->params [arg], value)) {
2901 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in argument store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
2904 if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC))
2905 ctx->has_this_store = 1;
2908 static void
2909 store_local (VerifyContext *ctx, guint32 arg)
2911 ILStackDesc *value;
2912 if (arg >= ctx->num_locals) {
2913 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", arg + 1, ctx->ip_offset));
2914 return;
2917 /*TODO verify definite assigment */
2918 if (!check_underflow (ctx, 1))
2919 return;
2921 value = stack_pop (ctx);
2922 if (ctx->locals [arg]->byref) {
2923 if (stack_slot_is_managed_mutability_pointer (value))
2924 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));
2926 if (local_is_safe_byref (ctx, arg) && !stack_slot_is_safe_byref (value))
2927 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot store an unsafe ret byref to a local that was previously stored a save ret byref value at 0x%04x", ctx->ip_offset));
2929 if (stack_slot_is_safe_byref (value) && !local_is_unsafe_byref (ctx, arg))
2930 ctx->locals_verification_state [arg] |= SAFE_BYREF_LOCAL;
2932 if (!stack_slot_is_safe_byref (value))
2933 ctx->locals_verification_state [arg] |= UNSAFE_BYREF_LOCAL;
2936 if (!verify_stack_type_compatibility (ctx, ctx->locals [arg], value)) {
2937 char *expected = mono_type_full_name (ctx->locals [arg]);
2938 char *found = stack_slot_full_name (value);
2939 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type '%s' on stack cannot be stored to local %d with type '%s' at 0x%04x",
2940 found,
2941 arg,
2942 expected,
2943 ctx->ip_offset));
2944 g_free (expected);
2945 g_free (found);
2949 /*FIXME add and sub needs special care here*/
2950 static void
2951 do_binop (VerifyContext *ctx, unsigned int opcode, const unsigned char table [TYPE_MAX][TYPE_MAX])
2953 ILStackDesc *a, *b, *top;
2954 int idxa, idxb, complexMerge = 0;
2955 unsigned char res;
2957 if (!check_underflow (ctx, 2))
2958 return;
2959 b = stack_pop (ctx);
2960 a = stack_pop (ctx);
2962 idxa = stack_slot_get_underlying_type (a);
2963 if (stack_slot_is_managed_pointer (a)) {
2964 idxa = TYPE_PTR;
2965 complexMerge = 1;
2968 idxb = stack_slot_get_underlying_type (b);
2969 if (stack_slot_is_managed_pointer (b)) {
2970 idxb = TYPE_PTR;
2971 complexMerge = 2;
2974 --idxa;
2975 --idxb;
2976 res = table [idxa][idxb];
2978 VERIFIER_DEBUG ( printf ("binop res %d\n", res); );
2979 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
2981 top = stack_push (ctx);
2982 if (res == TYPE_INV) {
2983 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)));
2984 copy_stack_value (top, a);
2985 return;
2988 if (res & NON_VERIFIABLE_RESULT) {
2989 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)));
2991 res = res & ~NON_VERIFIABLE_RESULT;
2994 if (complexMerge && res == TYPE_PTR) {
2995 if (complexMerge == 1)
2996 copy_stack_value (top, a);
2997 else if (complexMerge == 2)
2998 copy_stack_value (top, b);
3000 * There is no need to merge the type of two pointers.
3001 * The only valid operation is subtraction, that returns a native
3002 * int as result and can be used with any 2 pointer kinds.
3003 * This is valid acording to Patition III 1.1.4
3005 } else
3006 top->stype = res;
3011 static void
3012 do_boolean_branch_op (VerifyContext *ctx, int delta)
3014 int target = ctx->ip_offset + delta;
3015 ILStackDesc *top;
3017 VERIFIER_DEBUG ( printf ("boolean branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
3019 if (target < 0 || target >= ctx->code_size) {
3020 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Boolean branch target out of code at 0x%04x", ctx->ip_offset));
3021 return;
3024 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
3025 case 1:
3026 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3027 break;
3028 case 2:
3029 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3030 return;
3033 ctx->target = target;
3035 if (!check_underflow (ctx, 1))
3036 return;
3038 top = stack_pop (ctx);
3039 if (!is_valid_bool_arg (top))
3040 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));
3042 check_unmanaged_pointer (ctx, top);
3045 static gboolean
3046 stack_slot_is_complex_type_not_reference_type (ILStackDesc *slot)
3048 return stack_slot_get_type (slot) == TYPE_COMPLEX && !MONO_TYPE_IS_REFERENCE (slot->type) && !stack_slot_is_boxed_value (slot);
3051 static gboolean
3052 stack_slot_is_reference_value (ILStackDesc *slot)
3054 return stack_slot_get_type (slot) == TYPE_COMPLEX && (MONO_TYPE_IS_REFERENCE (slot->type) || stack_slot_is_boxed_value (slot));
3057 static void
3058 do_branch_op (VerifyContext *ctx, signed int delta, const unsigned char table [TYPE_MAX][TYPE_MAX])
3060 ILStackDesc *a, *b;
3061 int idxa, idxb;
3062 unsigned char res;
3063 int target = ctx->ip_offset + delta;
3065 VERIFIER_DEBUG ( printf ("branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
3067 if (target < 0 || target >= ctx->code_size) {
3068 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
3069 return;
3072 switch (is_valid_cmp_branch_instruction (ctx->header, ctx->ip_offset, target)) {
3073 case 1: /*FIXME use constants and not magic numbers.*/
3074 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3075 break;
3076 case 2:
3077 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3078 return;
3081 ctx->target = target;
3083 if (!check_underflow (ctx, 2))
3084 return;
3086 b = stack_pop (ctx);
3087 a = stack_pop (ctx);
3089 idxa = stack_slot_get_underlying_type (a);
3090 if (stack_slot_is_managed_pointer (a))
3091 idxa = TYPE_PTR;
3093 idxb = stack_slot_get_underlying_type (b);
3094 if (stack_slot_is_managed_pointer (b))
3095 idxb = TYPE_PTR;
3097 if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
3098 res = TYPE_INV;
3099 } else {
3100 --idxa;
3101 --idxb;
3102 res = table [idxa][idxb];
3105 VERIFIER_DEBUG ( printf ("branch res %d\n", res); );
3106 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
3108 if (res == TYPE_INV) {
3109 CODE_NOT_VERIFIABLE (ctx,
3110 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));
3111 } else if (res & NON_VERIFIABLE_RESULT) {
3112 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));
3113 res = res & ~NON_VERIFIABLE_RESULT;
3117 static void
3118 do_cmp_op (VerifyContext *ctx, const unsigned char table [TYPE_MAX][TYPE_MAX], guint32 opcode)
3120 ILStackDesc *a, *b;
3121 int idxa, idxb;
3122 unsigned char res;
3124 if (!check_underflow (ctx, 2))
3125 return;
3126 b = stack_pop (ctx);
3127 a = stack_pop (ctx);
3129 if (opcode == CEE_CGT_UN) {
3130 if ((stack_slot_is_reference_value (a) && stack_slot_is_null_literal (b)) ||
3131 (stack_slot_is_reference_value (b) && stack_slot_is_null_literal (a))) {
3132 stack_push_val (ctx, TYPE_I4, mono_get_int32_type ());
3133 return;
3137 idxa = stack_slot_get_underlying_type (a);
3138 if (stack_slot_is_managed_pointer (a))
3139 idxa = TYPE_PTR;
3141 idxb = stack_slot_get_underlying_type (b);
3142 if (stack_slot_is_managed_pointer (b))
3143 idxb = TYPE_PTR;
3145 if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
3146 res = TYPE_INV;
3147 } else {
3148 --idxa;
3149 --idxb;
3150 res = table [idxa][idxb];
3153 if(res == TYPE_INV) {
3154 char *left_type = stack_slot_full_name (a);
3155 char *right_type = stack_slot_full_name (b);
3156 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));
3157 g_free (left_type);
3158 g_free (right_type);
3159 } else if (res & NON_VERIFIABLE_RESULT) {
3160 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));
3161 res = res & ~NON_VERIFIABLE_RESULT;
3163 stack_push_val (ctx, TYPE_I4, mono_get_int32_type ());
3166 static void
3167 do_ret (VerifyContext *ctx)
3169 MonoType *ret = ctx->signature->ret;
3170 VERIFIER_DEBUG ( printf ("checking ret\n"); );
3171 if (ret->type != MONO_TYPE_VOID) {
3172 ILStackDesc *top;
3173 if (!check_underflow (ctx, 1))
3174 return;
3176 top = stack_pop(ctx);
3178 if (!verify_stack_type_compatibility (ctx, ctx->signature->ret, top)) {
3179 char *ret_type = mono_type_full_name (ctx->signature->ret);
3180 char *stack_type = stack_slot_full_name (top);
3181 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));
3182 g_free (stack_type);
3183 g_free (ret_type);
3184 return;
3187 if (ret->byref && !stack_slot_is_safe_byref (top))
3188 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method returns byref and return value is not a safe-to-return-byref at 0x%04x", ctx->ip_offset));
3190 if (ret->type == MONO_TYPE_TYPEDBYREF || mono_type_is_value_type (ret, "System", "ArgIterator") || mono_type_is_value_type (ret, "System", "RuntimeArgumentHandle"))
3191 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method returns byref, TypedReference, ArgIterator or RuntimeArgumentHandle at 0x%04x", ctx->ip_offset));
3194 if (ctx->eval.size > 0) {
3195 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack not empty (%d) after ret at 0x%04x", ctx->eval.size, ctx->ip_offset));
3197 if (in_any_block (ctx->header, ctx->ip_offset))
3198 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ret cannot escape exception blocks at 0x%04x", ctx->ip_offset));
3202 * 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.
3203 * This is illegal but mono_get_method_full decoded it.
3204 * TODO handle calling .ctor outside one or calling the .ctor for other class but super
3206 static void
3207 do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual_)
3209 ERROR_DECL (error);
3210 int param_count, i;
3211 MonoMethodSignature *sig;
3212 ILStackDesc *value;
3213 MonoMethod *method;
3214 gboolean virt_check_this = FALSE;
3215 gboolean constrained = ctx->prefix_set & PREFIX_CONSTRAINED;
3217 if (!(method = verifier_load_method (ctx, method_token, virtual_ ? "callvirt" : "call")))
3218 return;
3220 if (virtual_) {
3221 CLEAR_PREFIX (ctx, PREFIX_CONSTRAINED);
3223 if (m_class_is_valuetype (method->klass)) // && !constrained ???
3224 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with valuetype method at 0x%04x", ctx->ip_offset));
3226 if ((method->flags & METHOD_ATTRIBUTE_STATIC))
3227 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with static method at 0x%04x", ctx->ip_offset));
3229 } else {
3230 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
3231 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use call with an abstract method at 0x%04x", ctx->ip_offset));
3233 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !mono_class_is_sealed (method->klass)) {
3234 virt_check_this = TRUE;
3235 ctx->code [ctx->ip_offset].flags |= IL_CODE_CALL_NONFINAL_VIRTUAL;
3239 if (!(sig = mono_method_get_signature_checked (method, ctx->image, method_token, ctx->generic_context, error))) {
3240 mono_error_cleanup (error);
3241 sig = mono_method_get_signature_checked (method, ctx->image, method_token, NULL, error);
3244 if (!sig) {
3245 char *name = mono_type_get_full_name (method->klass);
3246 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)));
3247 mono_error_cleanup (error);
3248 g_free (name);
3249 return;
3252 param_count = sig->param_count + sig->hasthis;
3253 if (!check_underflow (ctx, param_count))
3254 return;
3256 gboolean is_safe_byref_call = TRUE;
3258 for (i = sig->param_count - 1; i >= 0; --i) {
3259 VERIFIER_DEBUG ( printf ("verifying argument %d\n", i); );
3260 value = stack_pop (ctx);
3261 if (!verify_stack_type_compatibility (ctx, sig->params[i], value)) {
3262 char *stack_name = stack_slot_full_name (value);
3263 char *sig_name = mono_type_full_name (sig->params [i]);
3264 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));
3265 g_free (stack_name);
3266 g_free (sig_name);
3269 if (stack_slot_is_managed_mutability_pointer (value))
3270 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));
3272 if ((ctx->prefix_set & PREFIX_TAIL) && stack_slot_is_managed_pointer (value)) {
3273 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));
3274 return;
3276 if (stack_slot_is_managed_pointer (value) && !stack_slot_is_safe_byref (value))
3277 is_safe_byref_call = FALSE;
3280 if (sig->hasthis) {
3281 MonoType *type = m_class_get_byval_arg (method->klass);
3282 ILStackDesc copy;
3284 if (mono_method_is_constructor (method) && !m_class_is_valuetype (method->klass)) {
3285 if (IS_STRICT_MODE (ctx) && !mono_method_is_constructor (ctx->method))
3286 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor outside one at 0x%04x", ctx->ip_offset));
3287 if (IS_STRICT_MODE (ctx) && method->klass != m_class_get_parent (ctx->method->klass) && method->klass != ctx->method->klass)
3288 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));
3290 ctx->super_ctor_called = TRUE;
3291 value = stack_pop_safe (ctx);
3292 if (IS_STRICT_MODE (ctx) && (value->stype & THIS_POINTER_MASK) != THIS_POINTER_MASK)
3293 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid 'this ptr' argument for constructor at 0x%04x", ctx->ip_offset));
3294 if (!(value->stype & UNINIT_THIS_MASK))
3295 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Calling the base constructor on an initialized this pointer at 0x%04x", ctx->ip_offset));
3296 } else {
3297 value = stack_pop (ctx);
3300 copy_stack_value (&copy, value);
3301 //TODO we should extract this to a 'drop_byref_argument' and use everywhere
3302 //Other parts of the code suffer from the same issue of
3303 copy.type = mono_type_get_type_byval (copy.type);
3304 copy.stype &= ~POINTER_MASK;
3306 if (virt_check_this && !stack_slot_is_this_pointer (value) && !(m_class_is_valuetype (method->klass) || stack_slot_is_boxed_value (value)))
3307 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));
3309 if (constrained && virtual_) {
3310 if (!stack_slot_is_managed_pointer (value))
3311 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object is not a managed pointer for a constrained call at 0x%04x", ctx->ip_offset));
3312 if (!mono_metadata_type_equal_full (mono_type_get_type_byval (value->type), mono_type_get_underlying_type (ctx->constrained_type), TRUE))
3313 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object not compatible with constrained type at 0x%04x", ctx->ip_offset));
3314 copy.stype |= BOXED_MASK;
3315 copy.type = ctx->constrained_type;
3316 } else {
3317 if (stack_slot_is_managed_pointer (value) && !m_class_is_valuetype (mono_class_from_mono_type (value->type)))
3318 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));
3320 if (!virtual_ && m_class_is_valuetype (mono_class_from_mono_type (value->type)) && !m_class_is_valuetype (method->klass) && !stack_slot_is_boxed_value (value))
3321 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a valuetype baseclass at 0x%04x", ctx->ip_offset));
3323 if (virtual_ && m_class_is_valuetype (mono_class_from_mono_type (value->type)) && !stack_slot_is_boxed_value (value))
3324 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a valuetype with callvirt at 0x%04x", ctx->ip_offset));
3326 if (m_class_is_valuetype (method->klass) && (stack_slot_is_boxed_value (value) || !stack_slot_is_managed_pointer (value)))
3327 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));
3329 if (!verify_stack_type_compatibility (ctx, type, &copy)) {
3330 char *expected = mono_type_full_name (type);
3331 char *effective = stack_slot_full_name (&copy);
3332 char *method_name = mono_method_full_name (method, TRUE);
3333 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",
3334 expected, effective, method_name, ctx->ip_offset));
3335 g_free (method_name);
3336 g_free (effective);
3337 g_free (expected);
3340 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, mono_class_from_mono_type (value->type))) {
3341 char *name = mono_method_full_name (method, TRUE);
3342 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3343 g_free (name);
3346 } else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
3347 char *name = mono_method_full_name (method, TRUE);
3348 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3349 g_free (name);
3352 if (sig->ret->type != MONO_TYPE_VOID) {
3353 if (!mono_type_is_valid_in_context (ctx, sig->ret))
3354 return;
3356 if (check_overflow (ctx)) {
3357 value = stack_push (ctx);
3358 set_stack_value (ctx, value, sig->ret, FALSE);
3359 if ((ctx->prefix_set & PREFIX_READONLY) && m_class_get_rank (method->klass) && !strcmp (method->name, "Address")) {
3360 ctx->prefix_set &= ~PREFIX_READONLY;
3361 value->stype |= CMMP_MASK;
3363 if (sig->ret->byref && is_safe_byref_call)
3364 value->stype |= SAFE_BYREF_MASK;
3368 if ((ctx->prefix_set & PREFIX_TAIL)) {
3369 if (!mono_delegate_ret_equal (mono_method_signature (ctx->method)->ret, sig->ret))
3370 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call with incompatible return type at 0x%04x", ctx->ip_offset));
3371 if (ctx->header->code [ctx->ip_offset + 5] != CEE_RET)
3372 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call not followed by ret at 0x%04x", ctx->ip_offset));
3377 static void
3378 do_push_static_field (VerifyContext *ctx, int token, gboolean take_addr)
3380 MonoClassField *field;
3381 MonoClass *klass;
3382 if (!check_overflow (ctx))
3383 return;
3384 if (!take_addr)
3385 CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3387 if (!(field = verifier_load_field (ctx, token, &klass, take_addr ? "ldsflda" : "ldsfld")))
3388 return;
3390 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3391 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load non static field at 0x%04x", ctx->ip_offset));
3392 return;
3394 /*taking the address of initonly field only works from the static constructor */
3395 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3396 !(field->parent == ctx->method->klass && (ctx->method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_STATIC)) && !strcmp (".cctor", ctx->method->name)))
3397 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only 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);
3402 ILStackDesc *value = stack_push (ctx);
3403 set_stack_value (ctx, value, field->type, take_addr);
3404 if (take_addr)
3405 value->stype |= SAFE_BYREF_MASK;
3408 static void
3409 do_store_static_field (VerifyContext *ctx, int token) {
3410 MonoClassField *field;
3411 MonoClass *klass;
3412 ILStackDesc *value;
3413 CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3415 if (!check_underflow (ctx, 1))
3416 return;
3418 value = stack_pop (ctx);
3420 if (!(field = verifier_load_field (ctx, token, &klass, "stsfld")))
3421 return;
3423 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3424 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store non static field at 0x%04x", ctx->ip_offset));
3425 return;
3428 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3429 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type in store static field at 0x%04x", ctx->ip_offset));
3430 return;
3433 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3434 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3436 if (!verify_stack_type_compatibility (ctx, field->type, value)) {
3437 char *stack_name = stack_slot_full_name (value);
3438 char *field_name = mono_type_full_name (field->type);
3439 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type in static field store expected '%s' but found '%s' at 0x%04x",
3440 field_name, stack_name, ctx->ip_offset));
3441 g_free (field_name);
3442 g_free (stack_name);
3446 static gboolean
3447 check_is_valid_type_for_field_ops (VerifyContext *ctx, int token, ILStackDesc *obj, MonoClassField **ret_field, const char *opcode)
3449 MonoClassField *field;
3450 MonoClass *klass;
3451 gboolean is_pointer;
3453 /*must be a reference type, a managed pointer, an unamanaged pointer, or a valuetype*/
3454 if (!(field = verifier_load_field (ctx, token, &klass, opcode)))
3455 return FALSE;
3457 *ret_field = field;
3458 //the value on stack is going to be used as a pointer
3459 is_pointer = stack_slot_get_type (obj) == TYPE_PTR || (stack_slot_get_type (obj) == TYPE_NATIVE_INT && !get_stack_type (m_class_get_byval_arg (field->parent)));
3461 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3462 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type at 0x%04x", ctx->ip_offset));
3463 return FALSE;
3465 g_assert (obj->type);
3467 /*The value on the stack must be a subclass of the defining type of the field*/
3468 /* we need to check if we can load the field from the stack value*/
3469 if (is_pointer) {
3470 if (stack_slot_get_underlying_type (obj) == TYPE_NATIVE_INT)
3471 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Native int is not a verifiable type to reference a field at 0x%04x", ctx->ip_offset));
3473 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3474 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3475 } else {
3476 if (!m_class_is_valuetype (field->parent) && stack_slot_is_managed_pointer (obj))
3477 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));
3479 /*a value type can be loaded from a value or a managed pointer, but not a boxed object*/
3480 if (m_class_is_valuetype (field->parent) && stack_slot_is_boxed_value (obj))
3481 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));
3483 if (!stack_slot_is_null_literal (obj) && !verify_stack_type_compatibility_full (ctx, m_class_get_byval_arg (field->parent), obj, TRUE, FALSE)) {
3484 char *found = stack_slot_full_name (obj);
3485 char *expected = mono_type_full_name (m_class_get_byval_arg (field->parent));
3486 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));
3487 g_free (found);
3488 g_free (expected);
3491 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, mono_class_from_mono_type (obj->type)))
3492 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3495 check_unmanaged_pointer (ctx, obj);
3496 return TRUE;
3499 static void
3500 do_push_field (VerifyContext *ctx, int token, gboolean take_addr)
3502 ILStackDesc *obj;
3503 MonoClassField *field;
3504 gboolean is_safe_byref = FALSE;
3506 if (!take_addr)
3507 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3509 if (!check_underflow (ctx, 1))
3510 return;
3511 obj = stack_pop_safe (ctx);
3513 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, take_addr ? "ldflda" : "ldfld"))
3514 return;
3516 if (take_addr && m_class_is_valuetype (field->parent) && !stack_slot_is_managed_pointer (obj))
3517 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a temporary value-type at 0x%04x", ctx->ip_offset));
3519 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3520 !(field->parent == ctx->method->klass && mono_method_is_constructor (ctx->method)))
3521 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
3523 //must do it here cuz stack_push will return the same slot as obj above
3524 is_safe_byref = take_addr && (stack_slot_is_reference_value (obj) || stack_slot_is_safe_byref (obj));
3526 ILStackDesc *value = stack_push (ctx);
3527 set_stack_value (ctx, value, field->type, take_addr);
3529 if (is_safe_byref)
3530 value->stype |= SAFE_BYREF_MASK;
3533 static void
3534 do_store_field (VerifyContext *ctx, int token)
3536 ILStackDesc *value, *obj;
3537 MonoClassField *field;
3538 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3540 if (!check_underflow (ctx, 2))
3541 return;
3543 value = stack_pop (ctx);
3544 obj = stack_pop_safe (ctx);
3546 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, "stfld"))
3547 return;
3549 if (!verify_stack_type_compatibility (ctx, field->type, value))
3550 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in field store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3553 /*TODO proper handle for Nullable<T>*/
3554 static void
3555 do_box_value (VerifyContext *ctx, int klass_token)
3557 ILStackDesc *value;
3558 MonoType *type = get_boxable_mono_type (ctx, klass_token, "box");
3559 MonoClass *klass;
3561 if (!type)
3562 return;
3564 if (!check_underflow (ctx, 1))
3565 return;
3567 value = stack_pop (ctx);
3568 /*box is a nop for reference types*/
3570 if (stack_slot_get_underlying_type (value) == TYPE_COMPLEX && MONO_TYPE_IS_REFERENCE (value->type) && MONO_TYPE_IS_REFERENCE (type)) {
3571 stack_push_stack_val (ctx, value)->stype |= BOXED_MASK;
3572 return;
3576 if (!verify_stack_type_compatibility (ctx, type, value))
3577 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for boxing operation at 0x%04x", ctx->ip_offset));
3579 klass = mono_class_from_mono_type (type);
3580 if (mono_class_is_nullable (klass))
3581 type = m_class_get_byval_arg (mono_class_get_nullable_param (klass));
3582 stack_push_val (ctx, TYPE_COMPLEX | BOXED_MASK, type);
3585 static void
3586 do_unbox_value (VerifyContext *ctx, int klass_token)
3588 ILStackDesc *value;
3589 MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox");
3591 if (!type)
3592 return;
3594 if (!check_underflow (ctx, 1))
3595 return;
3597 if (!m_class_is_valuetype (mono_class_from_mono_type (type)))
3598 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid reference type for unbox at 0x%04x", ctx->ip_offset));
3600 value = stack_pop (ctx);
3602 /*Value should be: a boxed valuetype or a reference type*/
3603 if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3604 (stack_slot_is_boxed_value (value) || !m_class_is_valuetype (mono_class_from_mono_type (value->type)))))
3605 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));
3607 set_stack_value (ctx, value = stack_push (ctx), mono_type_get_type_byref (type), FALSE);
3608 value->stype |= CMMP_MASK;
3611 static void
3612 do_unbox_any (VerifyContext *ctx, int klass_token)
3614 ILStackDesc *value;
3615 MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox.any");
3617 if (!type)
3618 return;
3620 if (!check_underflow (ctx, 1))
3621 return;
3623 value = stack_pop (ctx);
3625 /*Value should be: a boxed valuetype or a reference type*/
3626 if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3627 (stack_slot_is_boxed_value (value) || !m_class_is_valuetype (mono_class_from_mono_type (value->type)))))
3628 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));
3630 set_stack_value (ctx, stack_push (ctx), type, FALSE);
3633 static void
3634 do_unary_math_op (VerifyContext *ctx, int op)
3636 ILStackDesc *value;
3637 if (!check_underflow (ctx, 1))
3638 return;
3639 value = stack_pop (ctx);
3640 switch (stack_slot_get_type (value)) {
3641 case TYPE_I4:
3642 case TYPE_I8:
3643 case TYPE_NATIVE_INT:
3644 break;
3645 case TYPE_R8:
3646 if (op == CEE_NEG)
3647 break;
3648 case TYPE_COMPLEX: /*only enums are ok*/
3649 if (mono_type_is_enum_type (value->type))
3650 break;
3651 default:
3652 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for unary not at 0x%04x", ctx->ip_offset));
3654 stack_push_stack_val (ctx, value);
3657 static void
3658 do_conversion (VerifyContext *ctx, int kind)
3660 ILStackDesc *value;
3661 if (!check_underflow (ctx, 1))
3662 return;
3663 value = stack_pop (ctx);
3665 switch (stack_slot_get_type (value)) {
3666 case TYPE_I4:
3667 case TYPE_I8:
3668 case TYPE_NATIVE_INT:
3669 case TYPE_R8:
3670 break;
3671 default:
3672 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));
3675 switch (kind) {
3676 case TYPE_I4:
3677 stack_push_val (ctx, TYPE_I4, mono_get_int32_type ());
3678 break;
3679 case TYPE_I8:
3680 stack_push_val (ctx,TYPE_I8, m_class_get_byval_arg (mono_defaults.int64_class));
3681 break;
3682 case TYPE_R8:
3683 stack_push_val (ctx, TYPE_R8, m_class_get_byval_arg (mono_defaults.double_class));
3684 break;
3685 case TYPE_NATIVE_INT:
3686 stack_push_val (ctx, TYPE_NATIVE_INT, mono_get_int_type ());
3687 break;
3688 default:
3689 g_error ("unknown type %02x in conversion", kind);
3694 static void
3695 do_load_token (VerifyContext *ctx, int token)
3697 ERROR_DECL (error);
3698 gpointer handle;
3699 MonoClass *handle_class;
3700 if (!check_overflow (ctx))
3701 return;
3703 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
3704 handle = mono_method_get_wrapper_data (ctx->method, token);
3705 handle_class = (MonoClass *)mono_method_get_wrapper_data (ctx->method, token + 1);
3706 if (handle_class == mono_defaults.typehandle_class)
3707 handle = m_class_get_byval_arg ((MonoClass*)handle);
3708 } else {
3709 switch (token & 0xff000000) {
3710 case MONO_TOKEN_TYPE_DEF:
3711 case MONO_TOKEN_TYPE_REF:
3712 case MONO_TOKEN_TYPE_SPEC:
3713 case MONO_TOKEN_FIELD_DEF:
3714 case MONO_TOKEN_METHOD_DEF:
3715 case MONO_TOKEN_METHOD_SPEC:
3716 case MONO_TOKEN_MEMBER_REF:
3717 if (!token_bounds_check (ctx->image, token)) {
3718 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));
3719 return;
3721 break;
3722 default:
3723 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));
3724 return;
3727 handle = mono_ldtoken_checked (ctx->image, token, &handle_class, ctx->generic_context, error);
3730 if (!handle) {
3731 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)));
3732 mono_error_cleanup (error);
3733 return;
3735 if (handle_class == mono_defaults.typehandle_class) {
3736 mono_type_is_valid_in_context (ctx, (MonoType*)handle);
3737 } else if (handle_class == mono_defaults.methodhandle_class) {
3738 mono_method_is_valid_in_context (ctx, (MonoMethod*)handle);
3739 } else if (handle_class == mono_defaults.fieldhandle_class) {
3740 mono_type_is_valid_in_context (ctx, m_class_get_byval_arg (((MonoClassField*)handle)->parent));
3741 } else {
3742 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid ldtoken type %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
3744 stack_push_val (ctx, TYPE_COMPLEX, m_class_get_byval_arg (handle_class));
3747 static void
3748 do_ldobj_value (VerifyContext *ctx, int token)
3750 ILStackDesc *value;
3751 MonoType *type = get_boxable_mono_type (ctx, token, "ldobj");
3752 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3754 if (!type)
3755 return;
3757 if (!check_underflow (ctx, 1))
3758 return;
3760 value = stack_pop (ctx);
3761 if (!stack_slot_is_managed_pointer (value)
3762 && stack_slot_get_type (value) != TYPE_NATIVE_INT
3763 && !(stack_slot_get_type (value) == TYPE_PTR && value->type->type != MONO_TYPE_FNPTR)) {
3764 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid argument %s to ldobj at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3765 return;
3768 if (stack_slot_get_type (value) == TYPE_NATIVE_INT)
3769 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Using native pointer to ldobj at 0x%04x", ctx->ip_offset));
3771 /*We have a byval on the stack, but the comparison must be strict. */
3772 if (!verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (value->type), TRUE))
3773 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldojb operation at 0x%04x", ctx->ip_offset));
3775 set_stack_value (ctx, stack_push (ctx), type, FALSE);
3778 static void
3779 do_stobj (VerifyContext *ctx, int token)
3781 ILStackDesc *dest, *src;
3782 MonoType *type = get_boxable_mono_type (ctx, token, "stobj");
3783 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3785 if (!type)
3786 return;
3788 if (!check_underflow (ctx, 2))
3789 return;
3791 src = stack_pop (ctx);
3792 dest = stack_pop (ctx);
3794 if (stack_slot_is_managed_mutability_pointer (dest))
3795 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stobj at 0x%04x", ctx->ip_offset));
3797 if (!stack_slot_is_managed_pointer (dest))
3798 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of stobj operation at 0x%04x", ctx->ip_offset));
3800 if (stack_slot_is_boxed_value (src) && !MONO_TYPE_IS_REFERENCE (src->type) && !MONO_TYPE_IS_REFERENCE (type))
3801 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));
3803 if (!verify_stack_type_compatibility (ctx, type, src)) {
3804 char *type_name = mono_type_full_name (type);
3805 char *src_name = stack_slot_full_name (src);
3806 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));
3807 g_free (type_name);
3808 g_free (src_name);
3811 if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3812 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of stobj don't match at 0x%04x", ctx->ip_offset));
3815 static void
3816 do_cpobj (VerifyContext *ctx, int token)
3818 ILStackDesc *dest, *src;
3819 MonoType *type = get_boxable_mono_type (ctx, token, "cpobj");
3820 if (!type)
3821 return;
3823 if (!check_underflow (ctx, 2))
3824 return;
3826 src = stack_pop (ctx);
3827 dest = stack_pop (ctx);
3829 if (!stack_slot_is_managed_pointer (src))
3830 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid source of cpobj operation at 0x%04x", ctx->ip_offset));
3832 if (!stack_slot_is_managed_pointer (dest))
3833 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of cpobj operation at 0x%04x", ctx->ip_offset));
3835 if (stack_slot_is_managed_mutability_pointer (dest))
3836 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with cpobj at 0x%04x", ctx->ip_offset));
3838 if (!verify_type_compatibility (ctx, type, mono_type_get_type_byval (src->type)))
3839 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Token and source types of cpobj don't match at 0x%04x", ctx->ip_offset));
3841 if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3842 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of cpobj don't match at 0x%04x", ctx->ip_offset));
3845 static void
3846 do_initobj (VerifyContext *ctx, int token)
3848 ILStackDesc *obj;
3849 MonoType *stack, *type = get_boxable_mono_type (ctx, token, "initobj");
3850 if (!type)
3851 return;
3853 if (!check_underflow (ctx, 1))
3854 return;
3856 obj = stack_pop (ctx);
3858 if (!stack_slot_is_managed_pointer (obj))
3859 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid object address for initobj at 0x%04x", ctx->ip_offset));
3861 if (stack_slot_is_managed_mutability_pointer (obj))
3862 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with initobj at 0x%04x", ctx->ip_offset));
3864 stack = mono_type_get_type_byval (obj->type);
3865 if (MONO_TYPE_IS_REFERENCE (stack)) {
3866 if (!verify_type_compatibility (ctx, stack, type))
3867 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3868 else if (IS_STRICT_MODE (ctx) && !mono_metadata_type_equal (type, stack))
3869 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3870 } else if (!verify_type_compatibility (ctx, stack, type)) {
3871 char *expected_name = mono_type_full_name (type);
3872 char *stack_name = mono_type_full_name (stack);
3874 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));
3875 g_free (expected_name);
3876 g_free (stack_name);
3880 static void
3881 do_newobj (VerifyContext *ctx, int token)
3883 ILStackDesc *value;
3884 int i;
3885 MonoMethodSignature *sig;
3886 MonoMethod *method;
3887 gboolean is_delegate = FALSE;
3889 if (!(method = verifier_load_method (ctx, token, "newobj")))
3890 return;
3892 if (!mono_method_is_constructor (method)) {
3893 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method from token 0x%08x not a constructor at 0x%04x", token, ctx->ip_offset));
3894 return;
3897 if (mono_class_get_flags (method->klass) & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE))
3898 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Trying to instantiate an abstract or interface type at 0x%04x", ctx->ip_offset));
3900 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
3901 char *from = mono_method_full_name (ctx->method, TRUE);
3902 char *to = mono_method_full_name (method, TRUE);
3903 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);
3904 g_free (from);
3905 g_free (to);
3908 //FIXME use mono_method_get_signature_full
3909 sig = mono_method_signature (method);
3910 if (!sig) {
3911 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid constructor signature to newobj at 0x%04x", ctx->ip_offset));
3912 return;
3915 if (!sig->hasthis) {
3916 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid constructor signature missing hasthis at 0x%04x", ctx->ip_offset));
3917 return;
3920 if (!check_underflow (ctx, sig->param_count))
3921 return;
3923 is_delegate = m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class;
3925 if (is_delegate) {
3926 ILStackDesc *funptr;
3927 //first arg is object, second arg is fun ptr
3928 if (sig->param_count != 2) {
3929 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid delegate constructor at 0x%04x", ctx->ip_offset));
3930 return;
3932 funptr = stack_pop (ctx);
3933 value = stack_pop (ctx);
3934 verify_delegate_compatibility (ctx, method->klass, value, funptr);
3935 } else {
3936 for (i = sig->param_count - 1; i >= 0; --i) {
3937 VERIFIER_DEBUG ( printf ("verifying constructor argument %d\n", i); );
3938 value = stack_pop (ctx);
3939 if (!verify_stack_type_compatibility (ctx, sig->params [i], value)) {
3940 char *stack_name = stack_slot_full_name (value);
3941 char *sig_name = mono_type_full_name (sig->params [i]);
3942 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));
3943 g_free (stack_name);
3944 g_free (sig_name);
3947 if (stack_slot_is_managed_mutability_pointer (value))
3948 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer as argument of newobj at 0x%04x", ctx->ip_offset));
3952 if (check_overflow (ctx))
3953 set_stack_value (ctx, stack_push (ctx), m_class_get_byval_arg (method->klass), FALSE);
3956 static void
3957 do_cast (VerifyContext *ctx, int token, const char *opcode) {
3958 ILStackDesc *value;
3959 MonoType *type;
3960 gboolean is_boxed;
3961 gboolean do_box;
3963 if (!check_underflow (ctx, 1))
3964 return;
3966 if (!(type = get_boxable_mono_type (ctx, token, opcode)))
3967 return;
3969 if (type->byref) {
3970 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid %s type at 0x%04x", opcode, ctx->ip_offset));
3971 return;
3974 value = stack_pop (ctx);
3975 is_boxed = stack_slot_is_boxed_value (value);
3977 if (stack_slot_is_managed_pointer (value))
3978 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
3979 else if (!MONO_TYPE_IS_REFERENCE (value->type) && !is_boxed) {
3980 char *name = stack_slot_full_name (value);
3981 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));
3982 g_free (name);
3985 switch (value->type->type) {
3986 case MONO_TYPE_FNPTR:
3987 case MONO_TYPE_PTR:
3988 case MONO_TYPE_TYPEDBYREF:
3989 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
3990 default:
3991 break;
3994 do_box = is_boxed || mono_type_is_generic_argument(type) || m_class_is_valuetype (mono_class_from_mono_type (type));
3995 stack_push_val (ctx, TYPE_COMPLEX | (do_box ? BOXED_MASK : 0), type);
3998 static MonoType *
3999 mono_type_from_opcode (int opcode) {
4000 switch (opcode) {
4001 case CEE_LDIND_I1:
4002 case CEE_LDIND_U1:
4003 case CEE_STIND_I1:
4004 case CEE_LDELEM_I1:
4005 case CEE_LDELEM_U1:
4006 case CEE_STELEM_I1:
4007 return m_class_get_byval_arg (mono_defaults.sbyte_class);
4009 case CEE_LDIND_I2:
4010 case CEE_LDIND_U2:
4011 case CEE_STIND_I2:
4012 case CEE_LDELEM_I2:
4013 case CEE_LDELEM_U2:
4014 case CEE_STELEM_I2:
4015 return m_class_get_byval_arg (mono_defaults.int16_class);
4017 case CEE_LDIND_I4:
4018 case CEE_LDIND_U4:
4019 case CEE_STIND_I4:
4020 case CEE_LDELEM_I4:
4021 case CEE_LDELEM_U4:
4022 case CEE_STELEM_I4:
4023 return mono_get_int32_type ();
4025 case CEE_LDIND_I8:
4026 case CEE_STIND_I8:
4027 case CEE_LDELEM_I8:
4028 case CEE_STELEM_I8:
4029 return m_class_get_byval_arg (mono_defaults.int64_class);
4031 case CEE_LDIND_R4:
4032 case CEE_STIND_R4:
4033 case CEE_LDELEM_R4:
4034 case CEE_STELEM_R4:
4035 return m_class_get_byval_arg (mono_defaults.single_class);
4037 case CEE_LDIND_R8:
4038 case CEE_STIND_R8:
4039 case CEE_LDELEM_R8:
4040 case CEE_STELEM_R8:
4041 return m_class_get_byval_arg (mono_defaults.double_class);
4043 case CEE_LDIND_I:
4044 case CEE_STIND_I:
4045 case CEE_LDELEM_I:
4046 case CEE_STELEM_I:
4047 return mono_get_int_type ();
4049 case CEE_LDIND_REF:
4050 case CEE_STIND_REF:
4051 case CEE_LDELEM_REF:
4052 case CEE_STELEM_REF:
4053 return mono_get_object_type ();
4055 default:
4056 g_error ("unknown opcode %02x in mono_type_from_opcode ", opcode);
4057 return NULL;
4061 static void
4062 do_load_indirect (VerifyContext *ctx, int opcode)
4064 ILStackDesc *value;
4065 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
4067 if (!check_underflow (ctx, 1))
4068 return;
4070 value = stack_pop (ctx);
4071 if (!stack_slot_is_managed_pointer (value)) {
4072 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Load indirect not using a manager pointer at 0x%04x", ctx->ip_offset));
4073 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
4074 return;
4077 if (opcode == CEE_LDIND_REF) {
4078 if (stack_slot_get_underlying_type (value) != TYPE_COMPLEX || m_class_is_valuetype (mono_class_from_mono_type (value->type)))
4079 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind_ref expected object byref operation at 0x%04x", ctx->ip_offset));
4080 set_stack_value (ctx, stack_push (ctx), mono_type_get_type_byval (value->type), FALSE);
4081 } else {
4082 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (value->type), TRUE))
4083 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4084 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
4088 static void
4089 do_store_indirect (VerifyContext *ctx, int opcode)
4091 ILStackDesc *addr, *val;
4092 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
4094 if (!check_underflow (ctx, 2))
4095 return;
4097 val = stack_pop (ctx);
4098 addr = stack_pop (ctx);
4100 check_unmanaged_pointer (ctx, addr);
4102 if (!stack_slot_is_managed_pointer (addr) && stack_slot_get_type (addr) != TYPE_PTR) {
4103 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid non-pointer argument to stind at 0x%04x", ctx->ip_offset));
4104 return;
4107 if (stack_slot_is_managed_mutability_pointer (addr)) {
4108 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stind at 0x%04x", ctx->ip_offset));
4109 return;
4112 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (addr->type), TRUE))
4113 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid addr type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4115 if (!verify_stack_type_compatibility (ctx, mono_type_from_opcode (opcode), val))
4116 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4119 static void
4120 do_newarr (VerifyContext *ctx, int token)
4122 ILStackDesc *value;
4123 MonoType *type = get_boxable_mono_type (ctx, token, "newarr");
4125 if (!type)
4126 return;
4128 if (!check_underflow (ctx, 1))
4129 return;
4131 value = stack_pop (ctx);
4132 if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
4133 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));
4135 set_stack_value (ctx, stack_push (ctx), m_class_get_byval_arg (mono_class_create_array (mono_class_from_mono_type (type), 1)), FALSE);
4138 /*FIXME handle arrays that are not 0-indexed*/
4139 static void
4140 do_ldlen (VerifyContext *ctx)
4142 ILStackDesc *value;
4144 if (!check_underflow (ctx, 1))
4145 return;
4147 value = stack_pop (ctx);
4149 if (stack_slot_get_type (value) != TYPE_COMPLEX || value->type->type != MONO_TYPE_SZARRAY)
4150 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type for ldlen at 0x%04x", ctx->ip_offset));
4152 stack_push_val (ctx, TYPE_NATIVE_INT, mono_get_int_type ());
4155 /*FIXME handle arrays that are not 0-indexed*/
4156 /*FIXME handle readonly prefix and CMMP*/
4157 static void
4158 do_ldelema (VerifyContext *ctx, int klass_token)
4160 ILStackDesc *index, *array, *res;
4161 MonoType *type = get_boxable_mono_type (ctx, klass_token, "ldelema");
4162 gboolean valid;
4164 if (!type)
4165 return;
4167 if (!check_underflow (ctx, 2))
4168 return;
4170 index = stack_pop (ctx);
4171 array = stack_pop (ctx);
4173 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4174 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));
4176 if (!stack_slot_is_null_literal (array)) {
4177 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
4178 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type(%s) for ldelema at 0x%04x", stack_slot_get_name (array), ctx->ip_offset));
4179 else {
4180 if (get_stack_type (type) == TYPE_I4 || get_stack_type (type) == TYPE_NATIVE_INT) {
4181 valid = verify_type_compatibility_full (ctx, type, m_class_get_byval_arg (array->type->data.klass), TRUE);
4182 } else {
4183 valid = mono_metadata_type_equal (type, m_class_get_byval_arg (array->type->data.klass));
4185 if (!valid)
4186 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelema at 0x%04x", ctx->ip_offset));
4190 res = stack_push (ctx);
4191 set_stack_value (ctx, res, type, TRUE);
4192 if (ctx->prefix_set & PREFIX_READONLY) {
4193 ctx->prefix_set &= ~PREFIX_READONLY;
4194 res->stype |= CMMP_MASK;
4197 res->stype |= SAFE_BYREF_MASK;
4201 * FIXME handle arrays that are not 0-indexed
4202 * FIXME handle readonly prefix and CMMP
4204 static void
4205 do_ldelem (VerifyContext *ctx, int opcode, int token)
4207 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
4208 ILStackDesc *index, *array;
4209 MonoType *type;
4210 if (!check_underflow (ctx, 2))
4211 return;
4213 if (opcode == CEE_LDELEM) {
4214 if (!(type = verifier_load_type (ctx, token, "ldelem.any"))) {
4215 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
4216 return;
4218 } else {
4219 type = mono_type_from_opcode (opcode);
4222 index = stack_pop (ctx);
4223 array = stack_pop (ctx);
4225 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4226 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));
4228 if (!stack_slot_is_null_literal (array)) {
4229 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
4230 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));
4231 else {
4232 if (opcode == CEE_LDELEM_REF) {
4233 if (m_class_is_valuetype (array->type->data.klass))
4234 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for ldelem.ref 0x%04x", ctx->ip_offset));
4235 type = m_class_get_byval_arg (array->type->data.klass);
4236 } else {
4237 MonoType *candidate = m_class_get_byval_arg (array->type->data.klass);
4238 if (IS_STRICT_MODE (ctx)) {
4239 MonoType *underlying_type = mono_type_get_underlying_type_any (type);
4240 MonoType *underlying_candidate = mono_type_get_underlying_type_any (candidate);
4241 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)) ||
4242 (IS_ONE_OF2 (underlying_candidate->type, MONO_TYPE_I4, MONO_TYPE_U4) && IS_ONE_OF2 (underlying_type->type, MONO_TYPE_I, MONO_TYPE_U)))
4243 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
4245 if (!verify_type_compatibility_full (ctx, type, candidate, TRUE))
4246 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
4251 set_stack_value (ctx, stack_push (ctx), type, FALSE);
4252 #undef IS_ONE_OF2
4256 * FIXME handle arrays that are not 0-indexed
4258 static void
4259 do_stelem (VerifyContext *ctx, int opcode, int token)
4261 ILStackDesc *index, *array, *value;
4262 MonoType *type;
4263 if (!check_underflow (ctx, 3))
4264 return;
4266 if (opcode == CEE_STELEM) {
4267 if (!(type = verifier_load_type (ctx, token, "stelem.any"))) {
4268 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
4269 return;
4271 } else {
4272 type = mono_type_from_opcode (opcode);
4275 value = stack_pop (ctx);
4276 index = stack_pop (ctx);
4277 array = stack_pop (ctx);
4279 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4280 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));
4282 if (!stack_slot_is_null_literal (array)) {
4283 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY) {
4284 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));
4285 } else {
4286 if (opcode == CEE_STELEM_REF) {
4287 if (m_class_is_valuetype (array->type->data.klass))
4288 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4289 } else if (!verify_type_compatibility_full (ctx, m_class_get_byval_arg (array->type->data.klass), type, TRUE)) {
4290 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4294 if (opcode == CEE_STELEM_REF) {
4295 if (!stack_slot_is_boxed_value (value) && m_class_is_valuetype (mono_class_from_mono_type (value->type)))
4296 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4297 } else if (opcode != CEE_STELEM_REF) {
4298 if (!verify_stack_type_compatibility (ctx, type, value))
4299 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4301 if (stack_slot_is_boxed_value (value) && !MONO_TYPE_IS_REFERENCE (value->type) && !MONO_TYPE_IS_REFERENCE (type))
4302 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));
4307 static void
4308 do_throw (VerifyContext *ctx)
4310 ILStackDesc *exception;
4311 if (!check_underflow (ctx, 1))
4312 return;
4313 exception = stack_pop (ctx);
4315 if (!stack_slot_is_null_literal (exception) && !(stack_slot_get_type (exception) == TYPE_COMPLEX && !m_class_is_valuetype (mono_class_from_mono_type (exception->type))))
4316 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type on stack for throw, expected reference type at 0x%04x", ctx->ip_offset));
4318 if (mono_type_is_generic_argument (exception->type) && !stack_slot_is_boxed_value (exception)) {
4319 char *name = mono_type_full_name (exception->type);
4320 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));
4321 g_free (name);
4323 /*The stack is left empty after a throw*/
4324 ctx->eval.size = 0;
4328 static void
4329 do_endfilter (VerifyContext *ctx)
4331 MonoExceptionClause *clause;
4333 if (IS_STRICT_MODE (ctx)) {
4334 if (ctx->eval.size != 1)
4335 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack size must have one item for endfilter at 0x%04x", ctx->ip_offset));
4337 if (ctx->eval.size >= 1 && stack_slot_get_type (stack_pop (ctx)) != TYPE_I4)
4338 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack item type is not an int32 for endfilter at 0x%04x", ctx->ip_offset));
4341 if ((clause = is_correct_endfilter (ctx, ctx->ip_offset))) {
4342 if (IS_STRICT_MODE (ctx)) {
4343 if (ctx->ip_offset != clause->handler_offset - 2)
4344 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
4345 } else {
4346 if ((ctx->ip_offset != clause->handler_offset - 2) && !MONO_OFFSET_IN_HANDLER (clause, ctx->ip_offset))
4347 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
4349 } else {
4350 if (IS_STRICT_MODE (ctx) && !is_unverifiable_endfilter (ctx, ctx->ip_offset))
4351 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4352 else
4353 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4356 ctx->eval.size = 0;
4359 static void
4360 do_leave (VerifyContext *ctx, int delta)
4362 int target = ((gint32)ctx->ip_offset) + delta;
4363 if (target >= ctx->code_size || target < 0)
4364 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
4366 if (!is_correct_leave (ctx->header, ctx->ip_offset, target))
4367 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ctx->ip_offset));
4368 ctx->eval.size = 0;
4369 ctx->target = target;
4373 * do_static_branch:
4375 * Verify br and br.s opcodes.
4377 static void
4378 do_static_branch (VerifyContext *ctx, int delta)
4380 int target = ctx->ip_offset + delta;
4381 if (target < 0 || target >= ctx->code_size) {
4382 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("branch target out of code at 0x%04x", ctx->ip_offset));
4383 return;
4386 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4387 case 1:
4388 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4389 break;
4390 case 2:
4391 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4392 break;
4395 ctx->target = target;
4398 static void
4399 do_switch (VerifyContext *ctx, int count, const unsigned char *data)
4401 int i, base = ctx->ip_offset + 5 + count * 4;
4402 ILStackDesc *value;
4404 if (!check_underflow (ctx, 1))
4405 return;
4407 value = stack_pop (ctx);
4409 if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
4410 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to switch at 0x%04x", ctx->ip_offset));
4412 for (i = 0; i < count; ++i) {
4413 int target = base + read32 (data + i * 4);
4415 if (target < 0 || target >= ctx->code_size) {
4416 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x out of code at 0x%04x", i, ctx->ip_offset));
4417 return;
4420 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4421 case 1:
4422 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4423 break;
4424 case 2:
4425 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4426 return;
4428 merge_stacks (ctx, &ctx->eval, &ctx->code [target], FALSE, TRUE);
4432 static void
4433 do_load_function_ptr (VerifyContext *ctx, guint32 token, gboolean virtual_)
4435 ILStackDesc *top;
4436 MonoMethod *method;
4438 if (virtual_ && !check_underflow (ctx, 1))
4439 return;
4441 if (!virtual_ && !check_overflow (ctx))
4442 return;
4444 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
4445 method = (MonoMethod *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
4446 if (!method) {
4447 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4448 return;
4450 } else {
4451 if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
4452 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4453 return;
4456 if (!(method = verifier_load_method (ctx, token, virtual_ ? "ldvirtfrn" : "ldftn")))
4457 return;
4460 if (mono_method_is_constructor (method))
4461 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldftn with a constructor at 0x%04x", ctx->ip_offset));
4463 if (virtual_) {
4464 ILStackDesc *top = stack_pop (ctx);
4466 if (stack_slot_get_type (top) != TYPE_COMPLEX || top->type->type == MONO_TYPE_VALUETYPE)
4467 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to ldvirtftn at 0x%04x", ctx->ip_offset));
4469 if (method->flags & METHOD_ATTRIBUTE_STATIC)
4470 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldvirtftn with a constructor at 0x%04x", ctx->ip_offset));
4472 if (!verify_stack_type_compatibility (ctx, m_class_get_byval_arg (method->klass), top))
4473 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unexpected object for ldvirtftn at 0x%04x", ctx->ip_offset));
4476 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL))
4477 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);
4479 top = stack_push_val(ctx, TYPE_PTR, mono_type_create_fnptr_from_mono_method (ctx, method));
4480 top->method = method;
4483 static void
4484 do_sizeof (VerifyContext *ctx, int token)
4486 MonoType *type;
4488 if (!(type = verifier_load_type (ctx, token, "sizeof")))
4489 return;
4491 if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
4492 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type at 0x%04x", ctx->ip_offset));
4493 return;
4496 if (type->type == MONO_TYPE_VOID) {
4497 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type at 0x%04x", ctx->ip_offset));
4498 return;
4501 if (check_overflow (ctx))
4502 set_stack_value (ctx, stack_push (ctx), m_class_get_byval_arg (mono_defaults.uint32_class), FALSE);
4505 /* Stack top can be of any type, the runtime doesn't care and treat everything as an int. */
4506 static void
4507 do_localloc (VerifyContext *ctx)
4509 if (ctx->eval.size != 1) {
4510 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4511 return;
4514 if (in_any_exception_block (ctx->header, ctx->ip_offset)) {
4515 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4516 return;
4519 /*TODO verify top type*/
4520 /* top = */ stack_pop (ctx);
4522 set_stack_value (ctx, stack_push (ctx), mono_get_int_type (), FALSE);
4523 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Instruction localloc in never verifiable at 0x%04x", ctx->ip_offset));
4526 static void
4527 do_ldstr (VerifyContext *ctx, guint32 token)
4529 ERROR_DECL (error);
4530 if (ctx->method->wrapper_type == MONO_WRAPPER_NONE && !image_is_dynamic (ctx->image)) {
4531 if (mono_metadata_token_code (token) != MONO_TOKEN_STRING) {
4532 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string token %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4533 return;
4536 if (!mono_verifier_verify_string_signature (ctx->image, mono_metadata_token_index (token), error)) {
4537 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string index %x at 0x%04x due to: %", token, ctx->ip_offset, mono_error_get_message (error)), MONO_EXCEPTION_BAD_IMAGE);
4538 mono_error_cleanup (error);
4539 return;
4543 if (check_overflow (ctx))
4544 stack_push_val (ctx, TYPE_COMPLEX, m_class_get_byval_arg (mono_defaults.string_class));
4547 static void
4548 do_refanyval (VerifyContext *ctx, int token)
4550 ILStackDesc *top;
4551 MonoType *type;
4552 if (!check_underflow (ctx, 1))
4553 return;
4555 if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4556 return;
4558 top = stack_pop (ctx);
4560 if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4561 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));
4563 set_stack_value (ctx, stack_push (ctx), type, TRUE);
4566 static void
4567 do_refanytype (VerifyContext *ctx)
4569 ILStackDesc *top;
4571 if (!check_underflow (ctx, 1))
4572 return;
4574 top = stack_pop (ctx);
4576 if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4577 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));
4579 set_stack_value (ctx, stack_push (ctx), m_class_get_byval_arg (mono_defaults.typehandle_class), FALSE);
4583 static void
4584 do_mkrefany (VerifyContext *ctx, int token)
4586 ILStackDesc *top;
4587 MonoType *type;
4588 if (!check_underflow (ctx, 1))
4589 return;
4591 if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4592 return;
4594 top = stack_pop (ctx);
4596 if (stack_slot_is_managed_mutability_pointer (top))
4597 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with mkrefany at 0x%04x", ctx->ip_offset));
4599 if (!stack_slot_is_managed_pointer (top)) {
4600 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));
4601 }else {
4602 MonoType *stack_type = mono_type_get_type_byval (top->type);
4603 if (MONO_TYPE_IS_REFERENCE (type) && !mono_metadata_type_equal (type, stack_type))
4604 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4606 if (!MONO_TYPE_IS_REFERENCE (type) && !verify_type_compatibility_full (ctx, type, stack_type, TRUE))
4607 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4610 set_stack_value (ctx, stack_push (ctx), m_class_get_byval_arg (mono_defaults.typed_reference_class), FALSE);
4613 static void
4614 do_ckfinite (VerifyContext *ctx)
4616 ILStackDesc *top;
4617 if (!check_underflow (ctx, 1))
4618 return;
4620 top = stack_pop (ctx);
4622 if (stack_slot_get_underlying_type (top) != TYPE_R8)
4623 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));
4624 stack_push_stack_val (ctx, top);
4627 * merge_stacks:
4628 * Merge the stacks and perform compat checks. The merge check if types of @from are mergeable with type of @to
4630 * @from holds new values for a given control path
4631 * @to holds the current values of a given control path
4633 * TODO we can eliminate the from argument as all callers pass &ctx->eval
4635 static void
4636 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external)
4638 ERROR_DECL (error);
4639 int i, j;
4640 stack_init (ctx, to);
4642 if (start) {
4643 if (to->flags == IL_CODE_FLAG_NOT_PROCESSED)
4644 from->size = 0;
4645 else
4646 stack_copy (&ctx->eval, to);
4647 goto end_verify;
4648 } else if (!(to->flags & IL_CODE_STACK_MERGED)) {
4649 stack_copy (to, &ctx->eval);
4650 goto end_verify;
4652 VERIFIER_DEBUG ( printf ("performing stack merge %d x %d\n", from->size, to->size); );
4654 if (from->size != to->size) {
4655 VERIFIER_DEBUG ( printf ("different stack sizes %d x %d at 0x%04x\n", from->size, to->size, ctx->ip_offset); );
4656 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));
4657 goto end_verify;
4660 //FIXME we need to preserve CMMP attributes
4661 //FIXME we must take null literals into consideration.
4662 for (i = 0; i < from->size; ++i) {
4663 ILStackDesc *new_slot = from->stack + i;
4664 ILStackDesc *old_slot = to->stack + i;
4665 MonoType *new_type = mono_type_from_stack_slot (new_slot);
4666 MonoType *old_type = mono_type_from_stack_slot (old_slot);
4667 MonoClass *old_class = mono_class_from_mono_type (old_type);
4668 MonoClass *new_class = mono_class_from_mono_type (new_type);
4669 MonoClass *match_class = NULL;
4671 // check for safe byref before the next steps override new_slot
4672 if (stack_slot_is_safe_byref (old_slot) ^ stack_slot_is_safe_byref (new_slot)) {
4673 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot merge stack at depth %d byref types are safe byref incompatible at %0x04x ", i, ctx->ip_offset));
4674 goto end_verify;
4677 // S := T then U = S (new value is compatible with current value, keep current)
4678 if (verify_stack_type_compatibility (ctx, old_type, new_slot)) {
4679 copy_stack_value (new_slot, old_slot);
4680 continue;
4683 // T := S then U = T (old value is compatible with current value, use new)
4684 if (verify_stack_type_compatibility (ctx, new_type, old_slot)) {
4685 copy_stack_value (old_slot, new_slot);
4686 continue;
4689 /*Both slots are the same boxed valuetype. Simply copy it.*/
4690 if (stack_slot_is_boxed_value (old_slot) &&
4691 stack_slot_is_boxed_value (new_slot) &&
4692 mono_metadata_type_equal (old_type, new_type)) {
4693 copy_stack_value (new_slot, old_slot);
4694 continue;
4697 if (mono_type_is_generic_argument (old_type) || mono_type_is_generic_argument (new_type)) {
4698 char *old_name = stack_slot_full_name (old_slot);
4699 char *new_name = stack_slot_full_name (new_slot);
4700 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));
4701 g_free (old_name);
4702 g_free (new_name);
4703 goto end_verify;
4706 //both are reference types, use closest common super type
4707 if (!m_class_is_valuetype (mono_class_from_mono_type (old_type))
4708 && !m_class_is_valuetype (mono_class_from_mono_type (new_type))
4709 && !stack_slot_is_managed_pointer (old_slot)
4710 && !stack_slot_is_managed_pointer (new_slot)) {
4712 mono_class_setup_supertypes (old_class);
4713 mono_class_setup_supertypes (new_class);
4715 MonoClass **old_class_supertypes = m_class_get_supertypes (old_class);
4716 MonoClass **new_class_supertypes = m_class_get_supertypes (new_class);
4717 for (j = MIN (m_class_get_idepth (old_class), m_class_get_idepth (new_class)) - 1; j > 0; --j) {
4718 if (mono_metadata_type_equal (m_class_get_byval_arg (old_class_supertypes [j]), m_class_get_byval_arg (new_class_supertypes [j]))) {
4719 match_class = old_class_supertypes [j];
4720 goto match_found;
4724 mono_class_setup_interfaces (old_class, error);
4725 if (!mono_error_ok (error)) {
4726 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));
4727 mono_error_cleanup (error);
4728 goto end_verify;
4730 mono_class_setup_interfaces (new_class, error);
4731 if (!mono_error_ok (error)) {
4732 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));
4733 mono_error_cleanup (error);
4734 goto end_verify;
4737 /* if old class is an interface that new class implements */
4738 if (mono_class_is_interface (old_class)) {
4739 if (verifier_class_is_assignable_from (old_class, new_class)) {
4740 match_class = old_class;
4741 goto match_found;
4743 MonoClass **old_class_interfaces = m_class_get_interfaces (old_class);
4744 guint16 old_class_interface_count = m_class_get_interface_count (old_class);
4745 for (j = 0; j < old_class_interface_count; ++j) {
4746 if (verifier_class_is_assignable_from (old_class_interfaces [j], new_class)) {
4747 match_class = old_class_interfaces [j];
4748 goto match_found;
4753 if (mono_class_is_interface (new_class)) {
4754 if (verifier_class_is_assignable_from (new_class, old_class)) {
4755 match_class = new_class;
4756 goto match_found;
4758 MonoClass **new_class_interfaces = m_class_get_interfaces (new_class);
4759 guint16 new_class_interface_count = m_class_get_interface_count (new_class);
4760 for (j = 0; j < new_class_interface_count; ++j) {
4761 if (verifier_class_is_assignable_from (new_class_interfaces [j], old_class)) {
4762 match_class = new_class_interfaces [j];
4763 goto match_found;
4768 //No decent super type found, use object
4769 match_class = mono_defaults.object_class;
4770 goto match_found;
4771 } 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)) {
4772 match_class = mono_defaults.object_class;
4773 goto match_found;
4777 char *old_name = stack_slot_full_name (old_slot);
4778 char *new_name = stack_slot_full_name (new_slot);
4779 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));
4780 g_free (old_name);
4781 g_free (new_name);
4783 set_stack_value (ctx, old_slot, m_class_get_byval_arg (new_class), stack_slot_is_managed_pointer (old_slot));
4784 goto end_verify;
4786 match_found:
4787 g_assert (match_class);
4788 set_stack_value (ctx, old_slot, m_class_get_byval_arg (match_class), stack_slot_is_managed_pointer (old_slot));
4789 set_stack_value (ctx, new_slot, m_class_get_byval_arg (match_class), stack_slot_is_managed_pointer (old_slot));
4790 continue;
4793 end_verify:
4794 if (external)
4795 to->flags |= IL_CODE_FLAG_WAS_TARGET;
4796 to->flags |= IL_CODE_STACK_MERGED;
4799 #define HANDLER_START(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER ? (clause)->data.filter_offset : clause->handler_offset)
4800 #define IS_CATCH_OR_FILTER(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER || (clause)->flags == MONO_EXCEPTION_CLAUSE_NONE)
4803 * is_clause_in_range :
4805 * Returns TRUE if either the protected block or the handler of @clause is in the @start - @end range.
4807 static gboolean
4808 is_clause_in_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4810 if (clause->try_offset >= start && clause->try_offset < end)
4811 return TRUE;
4812 if (HANDLER_START (clause) >= start && HANDLER_START (clause) < end)
4813 return TRUE;
4814 return FALSE;
4818 * is_clause_inside_range :
4820 * Returns TRUE if @clause lies completely inside the @start - @end range.
4822 static gboolean
4823 is_clause_inside_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4825 if (clause->try_offset < start || (clause->try_offset + clause->try_len) > end)
4826 return FALSE;
4827 if (HANDLER_START (clause) < start || (clause->handler_offset + clause->handler_len) > end)
4828 return FALSE;
4829 return TRUE;
4833 * is_clause_nested :
4835 * Returns TRUE if @nested is nested in @clause.
4837 static gboolean
4838 is_clause_nested (MonoExceptionClause *clause, MonoExceptionClause *nested)
4840 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (nested, clause->data.filter_offset, clause->handler_offset))
4841 return TRUE;
4842 return is_clause_inside_range (nested, clause->try_offset, clause->try_offset + clause->try_len) ||
4843 is_clause_inside_range (nested, clause->handler_offset, clause->handler_offset + clause->handler_len);
4846 /* Test the relationship between 2 exception clauses. Follow P.1 12.4.2.7 of ECMA
4847 * the each pair of exception must have the following properties:
4848 * - one is fully nested on another (the outer must not be a filter clause) (the nested one must come earlier)
4849 * - completely disjoin (none of the 3 regions of each entry overlap with the other 3)
4850 * - mutual protection (protected block is EXACT the same, handlers are disjoin and all handler are catch or all handler are filter)
4852 static void
4853 verify_clause_relationship (VerifyContext *ctx, MonoExceptionClause *clause, MonoExceptionClause *to_test)
4855 /*clause is nested*/
4856 if (to_test->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (clause, to_test->data.filter_offset, to_test->handler_offset)) {
4857 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clause inside filter"));
4858 return;
4861 /*wrong nesting order.*/
4862 if (is_clause_nested (clause, to_test)) {
4863 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Nested exception clause appears after enclosing clause"));
4864 return;
4867 /*mutual protection*/
4868 if (clause->try_offset == to_test->try_offset && clause->try_len == to_test->try_len) {
4869 /*handlers are not disjoint*/
4870 if (is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) {
4871 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception handlers overlap"));
4872 return;
4874 /* handlers are not catch or filter */
4875 if (!IS_CATCH_OR_FILTER (clause) || !IS_CATCH_OR_FILTER (to_test)) {
4876 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses with shared protected block are neither catch or filter"));
4877 return;
4879 /*OK*/
4880 return;
4883 /*not completelly disjoint*/
4884 if ((is_clause_in_range (to_test, clause->try_offset, clause->try_offset + clause->try_len) ||
4885 is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) && !is_clause_nested (to_test, clause))
4886 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses overlap"));
4889 #define code_bounds_check(size) \
4890 if (ADDP_IS_GREATER_OR_OVF (ip, size, end)) {\
4891 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Code overrun starting with 0x%x at 0x%04x", *ip, ctx.ip_offset)); \
4892 break; \
4895 static gboolean
4896 mono_opcode_is_prefix (int op)
4898 switch (op) {
4899 case MONO_CEE_UNALIGNED_:
4900 case MONO_CEE_VOLATILE_:
4901 case MONO_CEE_TAIL_:
4902 case MONO_CEE_CONSTRAINED_:
4903 case MONO_CEE_READONLY_:
4904 return TRUE;
4906 return FALSE;
4910 * FIXME: need to distinguish between valid and verifiable.
4911 * Need to keep track of types on the stack.
4915 * mono_method_verify:
4916 * Verify types for opcodes.
4918 GSList*
4919 mono_method_verify (MonoMethod *method, int level)
4921 ERROR_DECL (error);
4922 const unsigned char *ip, *code_start;
4923 const unsigned char *end;
4924 MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
4926 int i, n, need_merge = 0, start = 0;
4927 guint ip_offset = 0, prefix = 0;
4928 MonoGenericContext *generic_context = NULL;
4929 MonoImage *image;
4930 VerifyContext ctx;
4931 GSList *tmp;
4932 VERIFIER_DEBUG ( printf ("Verify IL for method %s %s %s\n", method->klass->name_space, method->klass->name, method->name); );
4934 init_verifier_stats ();
4936 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
4937 (method->flags & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT))) {
4938 return NULL;
4941 memset (&ctx, 0, sizeof (VerifyContext));
4943 //FIXME use mono_method_get_signature_full
4944 ctx.signature = mono_method_signature (method);
4945 if (!ctx.signature) {
4946 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method signature"));
4948 finish_collect_stats ();
4949 return ctx.list;
4951 if (!method->is_generic && !mono_class_is_gtd (method->klass) && ctx.signature->has_type_parameters) {
4952 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Method and signature don't match in terms of genericity"));
4953 finish_collect_stats ();
4954 return ctx.list;
4957 ctx.header = mono_method_get_header_checked (method, error);
4958 if (!ctx.header) {
4959 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method header due to %s", mono_error_get_message (error)));
4960 mono_error_cleanup (error);
4961 finish_collect_stats ();
4962 return ctx.list;
4964 ctx.method = method;
4965 code_start = ip = ctx.header->code;
4966 end = ip + ctx.header->code_size;
4967 ctx.image = image = m_class_get_image (method->klass);
4970 ctx.max_args = ctx.signature->param_count + ctx.signature->hasthis;
4971 ctx.max_stack = ctx.header->max_stack;
4972 ctx.verifiable = ctx.valid = 1;
4973 ctx.level = level;
4975 ctx.code = g_new (ILCodeDesc, ctx.header->code_size);
4976 ctx.code_size = ctx.header->code_size;
4977 _MEM_ALLOC (sizeof (ILCodeDesc) * ctx.header->code_size);
4979 memset(ctx.code, 0, sizeof (ILCodeDesc) * ctx.header->code_size);
4981 ctx.num_locals = ctx.header->num_locals;
4982 ctx.locals = (MonoType **)g_memdup (ctx.header->locals, sizeof (MonoType*) * ctx.header->num_locals);
4983 _MEM_ALLOC (sizeof (MonoType*) * ctx.header->num_locals);
4984 ctx.locals_verification_state = g_new0 (char, ctx.num_locals);
4986 if (ctx.num_locals > 0 && !ctx.header->init_locals)
4987 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Method with locals variable but without init locals set"));
4989 ctx.params = g_new (MonoType*, ctx.max_args);
4990 _MEM_ALLOC (sizeof (MonoType*) * ctx.max_args);
4992 if (ctx.signature->hasthis)
4993 ctx.params [0] = m_class_is_valuetype (method->klass) ? m_class_get_this_arg (method->klass) : m_class_get_byval_arg (method->klass);
4994 memcpy (ctx.params + ctx.signature->hasthis, ctx.signature->params, sizeof (MonoType *) * ctx.signature->param_count);
4996 if (ctx.signature->is_inflated)
4997 ctx.generic_context = generic_context = mono_method_get_context (method);
4999 if (!generic_context && (mono_class_is_gtd (method->klass) || method->is_generic)) {
5000 if (method->is_generic)
5001 ctx.generic_context = generic_context = &(mono_method_get_generic_container (method)->context);
5002 else
5003 ctx.generic_context = generic_context = &mono_class_get_generic_container (method->klass)->context;
5006 for (i = 0; i < ctx.num_locals; ++i) {
5007 MonoType *uninflated = ctx.locals [i];
5008 ctx.locals [i] = mono_class_inflate_generic_type_checked (ctx.locals [i], ctx.generic_context, error);
5009 if (!mono_error_ok (error)) {
5010 char *name = mono_type_full_name (ctx.locals [i] ? ctx.locals [i] : uninflated);
5011 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %d of type %s", i, name));
5012 g_free (name);
5013 mono_error_cleanup (error);
5014 /* we must not free (in cleanup) what was not yet allocated (but only copied) */
5015 ctx.num_locals = i;
5016 ctx.max_args = 0;
5017 goto cleanup;
5020 for (i = 0; i < ctx.max_args; ++i) {
5021 MonoType *uninflated = ctx.params [i];
5022 ctx.params [i] = mono_class_inflate_generic_type_checked (ctx.params [i], ctx.generic_context, error);
5023 if (!mono_error_ok (error)) {
5024 char *name = mono_type_full_name (ctx.params [i] ? ctx.params [i] : uninflated);
5025 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %d of type %s", i, name));
5026 g_free (name);
5027 mono_error_cleanup (error);
5028 /* we must not free (in cleanup) what was not yet allocated (but only copied) */
5029 ctx.max_args = i;
5030 goto cleanup;
5033 stack_init (&ctx, &ctx.eval);
5035 for (i = 0; i < ctx.num_locals; ++i) {
5036 if (!mono_type_is_valid_in_context (&ctx, ctx.locals [i]))
5037 break;
5038 if (get_stack_type (ctx.locals [i]) == TYPE_INV) {
5039 char *name = mono_type_full_name (ctx.locals [i]);
5040 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %i of type %s", i, name));
5041 g_free (name);
5042 break;
5047 for (i = 0; i < ctx.max_args; ++i) {
5048 if (!mono_type_is_valid_in_context (&ctx, ctx.params [i]))
5049 break;
5051 if (get_stack_type (ctx.params [i]) == TYPE_INV) {
5052 char *name = mono_type_full_name (ctx.params [i]);
5053 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %i of type %s", i, name));
5054 g_free (name);
5055 break;
5059 if (!ctx.valid)
5060 goto cleanup;
5062 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
5063 MonoExceptionClause *clause = ctx.header->clauses + i;
5064 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); );
5066 if (clause->try_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, ctx.code_size))
5067 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause out of bounds at 0x%04x", clause->try_offset));
5069 if (clause->try_len <= 0)
5070 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause len <= 0 at 0x%04x", clause->try_offset));
5072 if (clause->handler_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->handler_offset, clause->handler_len, ctx.code_size))
5073 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause out of bounds at 0x%04x", clause->try_offset));
5075 if (clause->handler_len <= 0)
5076 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause len <= 0 at 0x%04x", clause->try_offset));
5078 if (clause->try_offset < clause->handler_offset && ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, HANDLER_START (clause)))
5079 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try block (at 0x%04x) includes handler block (at 0x%04x)", clause->try_offset, clause->handler_offset));
5081 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5082 if (clause->data.filter_offset > ctx.code_size)
5083 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause out of bounds at 0x%04x", clause->try_offset));
5085 if (clause->data.filter_offset >= clause->handler_offset)
5086 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause must come before the handler clause at 0x%04x", clause->data.filter_offset));
5089 for (n = i + 1; n < ctx.header->num_clauses && ctx.valid; ++n)
5090 verify_clause_relationship (&ctx, clause, ctx.header->clauses + n);
5092 if (!ctx.valid)
5093 break;
5095 ctx.code [clause->try_offset].flags |= IL_CODE_FLAG_WAS_TARGET;
5096 if (clause->try_offset + clause->try_len < ctx.code_size)
5097 ctx.code [clause->try_offset + clause->try_len].flags |= IL_CODE_FLAG_WAS_TARGET;
5098 if (clause->handler_offset + clause->handler_len < ctx.code_size)
5099 ctx.code [clause->handler_offset + clause->handler_len].flags |= IL_CODE_FLAG_WAS_TARGET;
5101 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
5102 if (!clause->data.catch_class) {
5103 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Catch clause %d with invalid type", i));
5104 break;
5106 if (!mono_type_is_valid_in_context (&ctx, m_class_get_byval_arg (clause->data.catch_class)))
5107 break;
5109 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, clause->data.catch_class);
5111 else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5112 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->data.filter_offset, mono_defaults.exception_class);
5113 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, mono_defaults.exception_class);
5117 if (!ctx.valid)
5118 goto cleanup;
5120 original_bb = bb = mono_basic_block_split (method, error, ctx.header);
5121 if (!mono_error_ok (error)) {
5122 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid branch target: %s", mono_error_get_message (error)));
5123 mono_error_cleanup (error);
5124 goto cleanup;
5126 g_assert (bb);
5128 while (ip < end && ctx.valid) {
5129 int op_size;
5130 ip_offset = (guint) (ip - code_start);
5132 const unsigned char *ip_copy = ip;
5133 MonoOpcodeEnum op;
5135 if (ip_offset > bb->end) {
5136 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block at [0x%04x] targets middle instruction at 0x%04x", bb->end, ip_offset));
5137 goto cleanup;
5140 if (ip_offset == bb->end)
5141 bb = bb->next;
5143 op_size = mono_opcode_value_and_size (&ip_copy, end, &op);
5144 if (op_size == -1) {
5145 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ip_offset));
5146 goto cleanup;
5149 if (ADD_IS_GREATER_OR_OVF (ip_offset, op_size, bb->end)) {
5150 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block targets middle of instruction at 0x%04x", ip_offset));
5151 goto cleanup;
5154 /*Last Instruction*/
5155 if (ip_offset + op_size == bb->end && mono_opcode_is_prefix (op)) {
5156 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));
5157 goto cleanup;
5161 ctx.ip_offset = ip_offset = (guint) (ip - code_start);
5163 /*We need to check against fallthrou in and out of protected blocks.
5164 * For fallout we check the once a protected block ends, if the start flag is not set.
5165 * Likewise for fallthru in, we check if ip is the start of a protected block and start is not set
5166 * TODO convert these checks to be done using flags and not this loop
5168 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
5169 MonoExceptionClause *clause = ctx.header->clauses + i;
5171 if ((clause->try_offset + clause->try_len == ip_offset) && start == 0) {
5172 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru off try block at 0x%04x", ip_offset));
5173 start = 1;
5176 if ((clause->handler_offset + clause->handler_len == ip_offset) && start == 0) {
5177 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
5178 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
5179 else
5180 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
5181 start = 1;
5184 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && clause->handler_offset == ip_offset && start == 0) {
5185 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of filter block at 0x%04x", ip_offset));
5186 start = 1;
5189 if (clause->handler_offset == ip_offset && start == 0) {
5190 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru handler block at 0x%04x", ip_offset));
5191 start = 1;
5194 if (clause->try_offset == ip_offset && ctx.eval.size > 0 && start == 0) {
5195 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Try to enter try block with a non-empty stack at 0x%04x", ip_offset));
5196 start = 1;
5200 /*This must be done after fallthru detection otherwise it won't happen.*/
5201 if (bb->dead) {
5202 /*FIXME remove this once we move all bad branch checking code to use BB only*/
5203 ctx.code [ip_offset].flags |= IL_CODE_FLAG_SEEN;
5204 ip += op_size;
5205 continue;
5208 if (!ctx.valid)
5209 break;
5211 if (need_merge) {
5212 VERIFIER_DEBUG ( printf ("extra merge needed! 0x%04x \n", ctx.target); );
5213 merge_stacks (&ctx, &ctx.eval, &ctx.code [ctx.target], FALSE, TRUE);
5214 need_merge = 0;
5216 merge_stacks (&ctx, &ctx.eval, &ctx.code[ip_offset], start, FALSE);
5217 start = 0;
5219 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
5220 #ifdef MONO_VERIFIER_DEBUG
5222 char *discode;
5223 discode = mono_disasm_code_one (NULL, method, ip, NULL);
5224 discode [strlen (discode) - 1] = 0; /* no \n */
5225 g_print ("[%d] %-29s (%d)\n", ip_offset, discode, ctx.eval.size);
5226 g_free (discode);
5228 dump_stack_state (&ctx.code [ip_offset]);
5229 dump_stack_state (&ctx.eval);
5230 #endif
5232 switch (*ip) {
5233 case CEE_NOP:
5234 case CEE_BREAK:
5235 ++ip;
5236 break;
5238 case CEE_LDARG_0:
5239 case CEE_LDARG_1:
5240 case CEE_LDARG_2:
5241 case CEE_LDARG_3:
5242 push_arg (&ctx, *ip - CEE_LDARG_0, FALSE);
5243 ++ip;
5244 break;
5246 case CEE_LDARG_S:
5247 case CEE_LDARGA_S:
5248 code_bounds_check (2);
5249 push_arg (&ctx, ip [1], *ip == CEE_LDARGA_S);
5250 ip += 2;
5251 break;
5253 case CEE_ADD_OVF_UN:
5254 do_binop (&ctx, *ip, add_ovf_un_table);
5255 ++ip;
5256 break;
5258 case CEE_SUB_OVF_UN:
5259 do_binop (&ctx, *ip, sub_ovf_un_table);
5260 ++ip;
5261 break;
5263 case CEE_ADD_OVF:
5264 case CEE_SUB_OVF:
5265 case CEE_MUL_OVF:
5266 case CEE_MUL_OVF_UN:
5267 do_binop (&ctx, *ip, bin_ovf_table);
5268 ++ip;
5269 break;
5271 case CEE_ADD:
5272 do_binop (&ctx, *ip, add_table);
5273 ++ip;
5274 break;
5276 case CEE_SUB:
5277 do_binop (&ctx, *ip, sub_table);
5278 ++ip;
5279 break;
5281 case CEE_MUL:
5282 case CEE_DIV:
5283 case CEE_REM:
5284 do_binop (&ctx, *ip, bin_op_table);
5285 ++ip;
5286 break;
5288 case CEE_AND:
5289 case CEE_DIV_UN:
5290 case CEE_OR:
5291 case CEE_REM_UN:
5292 case CEE_XOR:
5293 do_binop (&ctx, *ip, int_bin_op_table);
5294 ++ip;
5295 break;
5297 case CEE_SHL:
5298 case CEE_SHR:
5299 case CEE_SHR_UN:
5300 do_binop (&ctx, *ip, shift_op_table);
5301 ++ip;
5302 break;
5304 case CEE_POP:
5305 if (!check_underflow (&ctx, 1))
5306 break;
5307 stack_pop_safe (&ctx);
5308 ++ip;
5309 break;
5311 case CEE_RET:
5312 do_ret (&ctx);
5313 ++ip;
5314 start = 1;
5315 break;
5317 case CEE_LDLOC_0:
5318 case CEE_LDLOC_1:
5319 case CEE_LDLOC_2:
5320 case CEE_LDLOC_3:
5321 /*TODO support definite assignment verification? */
5322 push_local (&ctx, *ip - CEE_LDLOC_0, FALSE);
5323 ++ip;
5324 break;
5326 case CEE_STLOC_0:
5327 case CEE_STLOC_1:
5328 case CEE_STLOC_2:
5329 case CEE_STLOC_3:
5330 store_local (&ctx, *ip - CEE_STLOC_0);
5331 ++ip;
5332 break;
5334 case CEE_STLOC_S:
5335 code_bounds_check (2);
5336 store_local (&ctx, ip [1]);
5337 ip += 2;
5338 break;
5340 case CEE_STARG_S:
5341 code_bounds_check (2);
5342 store_arg (&ctx, ip [1]);
5343 ip += 2;
5344 break;
5346 case CEE_LDC_I4_M1:
5347 case CEE_LDC_I4_0:
5348 case CEE_LDC_I4_1:
5349 case CEE_LDC_I4_2:
5350 case CEE_LDC_I4_3:
5351 case CEE_LDC_I4_4:
5352 case CEE_LDC_I4_5:
5353 case CEE_LDC_I4_6:
5354 case CEE_LDC_I4_7:
5355 case CEE_LDC_I4_8:
5356 if (check_overflow (&ctx))
5357 stack_push_val (&ctx, TYPE_I4, mono_get_int32_type ());
5358 ++ip;
5359 break;
5361 case CEE_LDC_I4_S:
5362 code_bounds_check (2);
5363 if (check_overflow (&ctx))
5364 stack_push_val (&ctx, TYPE_I4, mono_get_int32_type ());
5365 ip += 2;
5366 break;
5368 case CEE_LDC_I4:
5369 code_bounds_check (5);
5370 if (check_overflow (&ctx))
5371 stack_push_val (&ctx,TYPE_I4, mono_get_int32_type ());
5372 ip += 5;
5373 break;
5375 case CEE_LDC_I8:
5376 code_bounds_check (9);
5377 if (check_overflow (&ctx))
5378 stack_push_val (&ctx,TYPE_I8, m_class_get_byval_arg (mono_defaults.int64_class));
5379 ip += 9;
5380 break;
5382 case CEE_LDC_R4:
5383 code_bounds_check (5);
5384 if (check_overflow (&ctx))
5385 stack_push_val (&ctx, TYPE_R8, m_class_get_byval_arg (mono_defaults.double_class));
5386 ip += 5;
5387 break;
5389 case CEE_LDC_R8:
5390 code_bounds_check (9);
5391 if (check_overflow (&ctx))
5392 stack_push_val (&ctx, TYPE_R8, m_class_get_byval_arg (mono_defaults.double_class));
5393 ip += 9;
5394 break;
5396 case CEE_LDNULL:
5397 if (check_overflow (&ctx))
5398 stack_push_val (&ctx, TYPE_COMPLEX | NULL_LITERAL_MASK, mono_get_object_type ());
5399 ++ip;
5400 break;
5402 case CEE_BEQ_S:
5403 case CEE_BNE_UN_S:
5404 code_bounds_check (2);
5405 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_eq_op);
5406 ip += 2;
5407 need_merge = 1;
5408 break;
5410 case CEE_BGE_S:
5411 case CEE_BGT_S:
5412 case CEE_BLE_S:
5413 case CEE_BLT_S:
5414 case CEE_BGE_UN_S:
5415 case CEE_BGT_UN_S:
5416 case CEE_BLE_UN_S:
5417 case CEE_BLT_UN_S:
5418 code_bounds_check (2);
5419 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_op);
5420 ip += 2;
5421 need_merge = 1;
5422 break;
5424 case CEE_BEQ:
5425 case CEE_BNE_UN:
5426 code_bounds_check (5);
5427 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_eq_op);
5428 ip += 5;
5429 need_merge = 1;
5430 break;
5432 case CEE_BGE:
5433 case CEE_BGT:
5434 case CEE_BLE:
5435 case CEE_BLT:
5436 case CEE_BGE_UN:
5437 case CEE_BGT_UN:
5438 case CEE_BLE_UN:
5439 case CEE_BLT_UN:
5440 code_bounds_check (5);
5441 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_op);
5442 ip += 5;
5443 need_merge = 1;
5444 break;
5446 case CEE_LDLOC_S:
5447 case CEE_LDLOCA_S:
5448 code_bounds_check (2);
5449 push_local (&ctx, ip[1], *ip == CEE_LDLOCA_S);
5450 ip += 2;
5451 break;
5453 case CEE_UNUSED99:
5454 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5455 ++ip;
5456 break;
5458 case CEE_DUP: {
5459 ILStackDesc *top;
5460 if (!check_underflow (&ctx, 1))
5461 break;
5462 if (!check_overflow (&ctx))
5463 break;
5464 top = stack_push (&ctx);
5465 copy_stack_value (top, stack_peek (&ctx, 1));
5466 ++ip;
5467 break;
5470 case CEE_JMP:
5471 code_bounds_check (5);
5472 if (ctx.eval.size)
5473 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Eval stack must be empty in jmp at 0x%04x", ip_offset));
5474 /* token = read32 (ip + 1); */
5475 if (in_any_block (ctx.header, ip_offset))
5476 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("jmp cannot escape exception blocks at 0x%04x", ip_offset));
5478 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction jmp is not verifiable at 0x%04x", ctx.ip_offset));
5480 * FIXME: check signature, retval, arguments etc.
5482 ip += 5;
5483 break;
5484 case CEE_CALL:
5485 case CEE_CALLVIRT:
5486 code_bounds_check (5);
5487 do_invoke_method (&ctx, read32 (ip + 1), *ip == CEE_CALLVIRT);
5488 ip += 5;
5489 break;
5491 case CEE_CALLI:
5492 code_bounds_check (5);
5493 /* token = read32 (ip + 1); */
5495 * FIXME: check signature, retval, arguments etc.
5496 * FIXME: check requirements for tail call
5498 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction calli is not verifiable at 0x%04x", ctx.ip_offset));
5499 ip += 5;
5500 break;
5501 case CEE_BR_S:
5502 code_bounds_check (2);
5503 do_static_branch (&ctx, (signed char)ip [1] + 2);
5504 need_merge = 1;
5505 ip += 2;
5506 start = 1;
5507 break;
5509 case CEE_BRFALSE_S:
5510 case CEE_BRTRUE_S:
5511 code_bounds_check (2);
5512 do_boolean_branch_op (&ctx, (signed char)ip [1] + 2);
5513 ip += 2;
5514 need_merge = 1;
5515 break;
5517 case CEE_BR:
5518 code_bounds_check (5);
5519 do_static_branch (&ctx, (gint32)read32 (ip + 1) + 5);
5520 need_merge = 1;
5521 ip += 5;
5522 start = 1;
5523 break;
5525 case CEE_BRFALSE:
5526 case CEE_BRTRUE:
5527 code_bounds_check (5);
5528 do_boolean_branch_op (&ctx, (gint32)read32 (ip + 1) + 5);
5529 ip += 5;
5530 need_merge = 1;
5531 break;
5533 case CEE_SWITCH: {
5534 guint32 entries;
5535 code_bounds_check (5);
5536 entries = read32 (ip + 1);
5538 if (entries > 0xFFFFFFFFU / sizeof (guint32))
5539 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Too many switch entries %x at 0x%04x", entries, ctx.ip_offset));
5541 ip += 5;
5542 code_bounds_check (sizeof (guint32) * entries);
5544 do_switch (&ctx, entries, ip);
5545 ip += sizeof (guint32) * entries;
5546 break;
5548 case CEE_LDIND_I1:
5549 case CEE_LDIND_U1:
5550 case CEE_LDIND_I2:
5551 case CEE_LDIND_U2:
5552 case CEE_LDIND_I4:
5553 case CEE_LDIND_U4:
5554 case CEE_LDIND_I8:
5555 case CEE_LDIND_I:
5556 case CEE_LDIND_R4:
5557 case CEE_LDIND_R8:
5558 case CEE_LDIND_REF:
5559 do_load_indirect (&ctx, *ip);
5560 ++ip;
5561 break;
5563 case CEE_STIND_REF:
5564 case CEE_STIND_I1:
5565 case CEE_STIND_I2:
5566 case CEE_STIND_I4:
5567 case CEE_STIND_I8:
5568 case CEE_STIND_R4:
5569 case CEE_STIND_R8:
5570 case CEE_STIND_I:
5571 do_store_indirect (&ctx, *ip);
5572 ++ip;
5573 break;
5575 case CEE_NOT:
5576 case CEE_NEG:
5577 do_unary_math_op (&ctx, *ip);
5578 ++ip;
5579 break;
5581 case CEE_CONV_I1:
5582 case CEE_CONV_I2:
5583 case CEE_CONV_I4:
5584 case CEE_CONV_U1:
5585 case CEE_CONV_U2:
5586 case CEE_CONV_U4:
5587 do_conversion (&ctx, TYPE_I4);
5588 ++ip;
5589 break;
5591 case CEE_CONV_I8:
5592 case CEE_CONV_U8:
5593 do_conversion (&ctx, TYPE_I8);
5594 ++ip;
5595 break;
5597 case CEE_CONV_R4:
5598 case CEE_CONV_R8:
5599 case CEE_CONV_R_UN:
5600 do_conversion (&ctx, TYPE_R8);
5601 ++ip;
5602 break;
5604 case CEE_CONV_I:
5605 case CEE_CONV_U:
5606 do_conversion (&ctx, TYPE_NATIVE_INT);
5607 ++ip;
5608 break;
5610 case CEE_CPOBJ:
5611 code_bounds_check (5);
5612 do_cpobj (&ctx, read32 (ip + 1));
5613 ip += 5;
5614 break;
5616 case CEE_LDOBJ:
5617 code_bounds_check (5);
5618 do_ldobj_value (&ctx, read32 (ip + 1));
5619 ip += 5;
5620 break;
5622 case CEE_LDSTR:
5623 code_bounds_check (5);
5624 do_ldstr (&ctx, read32 (ip + 1));
5625 ip += 5;
5626 break;
5628 case CEE_NEWOBJ:
5629 code_bounds_check (5);
5630 do_newobj (&ctx, read32 (ip + 1));
5631 ip += 5;
5632 break;
5634 case CEE_CASTCLASS:
5635 case CEE_ISINST:
5636 code_bounds_check (5);
5637 do_cast (&ctx, read32 (ip + 1), *ip == CEE_CASTCLASS ? "castclass" : "isinst");
5638 ip += 5;
5639 break;
5641 case CEE_UNUSED58:
5642 case CEE_UNUSED1:
5643 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5644 ++ip;
5645 break;
5647 case CEE_UNBOX:
5648 code_bounds_check (5);
5649 do_unbox_value (&ctx, read32 (ip + 1));
5650 ip += 5;
5651 break;
5653 case CEE_THROW:
5654 do_throw (&ctx);
5655 start = 1;
5656 ++ip;
5657 break;
5659 case CEE_LDFLD:
5660 case CEE_LDFLDA:
5661 code_bounds_check (5);
5662 do_push_field (&ctx, read32 (ip + 1), *ip == CEE_LDFLDA);
5663 ip += 5;
5664 break;
5666 case CEE_LDSFLD:
5667 case CEE_LDSFLDA:
5668 code_bounds_check (5);
5669 do_push_static_field (&ctx, read32 (ip + 1), *ip == CEE_LDSFLDA);
5670 ip += 5;
5671 break;
5673 case CEE_STFLD:
5674 code_bounds_check (5);
5675 do_store_field (&ctx, read32 (ip + 1));
5676 ip += 5;
5677 break;
5679 case CEE_STSFLD:
5680 code_bounds_check (5);
5681 do_store_static_field (&ctx, read32 (ip + 1));
5682 ip += 5;
5683 break;
5685 case CEE_STOBJ:
5686 code_bounds_check (5);
5687 do_stobj (&ctx, read32 (ip + 1));
5688 ip += 5;
5689 break;
5691 case CEE_CONV_OVF_I1_UN:
5692 case CEE_CONV_OVF_I2_UN:
5693 case CEE_CONV_OVF_I4_UN:
5694 case CEE_CONV_OVF_U1_UN:
5695 case CEE_CONV_OVF_U2_UN:
5696 case CEE_CONV_OVF_U4_UN:
5697 do_conversion (&ctx, TYPE_I4);
5698 ++ip;
5699 break;
5701 case CEE_CONV_OVF_I8_UN:
5702 case CEE_CONV_OVF_U8_UN:
5703 do_conversion (&ctx, TYPE_I8);
5704 ++ip;
5705 break;
5707 case CEE_CONV_OVF_I_UN:
5708 case CEE_CONV_OVF_U_UN:
5709 do_conversion (&ctx, TYPE_NATIVE_INT);
5710 ++ip;
5711 break;
5713 case CEE_BOX:
5714 code_bounds_check (5);
5715 do_box_value (&ctx, read32 (ip + 1));
5716 ip += 5;
5717 break;
5719 case CEE_NEWARR:
5720 code_bounds_check (5);
5721 do_newarr (&ctx, read32 (ip + 1));
5722 ip += 5;
5723 break;
5725 case CEE_LDLEN:
5726 do_ldlen (&ctx);
5727 ++ip;
5728 break;
5730 case CEE_LDELEMA:
5731 code_bounds_check (5);
5732 do_ldelema (&ctx, read32 (ip + 1));
5733 ip += 5;
5734 break;
5736 case CEE_LDELEM_I1:
5737 case CEE_LDELEM_U1:
5738 case CEE_LDELEM_I2:
5739 case CEE_LDELEM_U2:
5740 case CEE_LDELEM_I4:
5741 case CEE_LDELEM_U4:
5742 case CEE_LDELEM_I8:
5743 case CEE_LDELEM_I:
5744 case CEE_LDELEM_R4:
5745 case CEE_LDELEM_R8:
5746 case CEE_LDELEM_REF:
5747 do_ldelem (&ctx, *ip, 0);
5748 ++ip;
5749 break;
5751 case CEE_STELEM_I:
5752 case CEE_STELEM_I1:
5753 case CEE_STELEM_I2:
5754 case CEE_STELEM_I4:
5755 case CEE_STELEM_I8:
5756 case CEE_STELEM_R4:
5757 case CEE_STELEM_R8:
5758 case CEE_STELEM_REF:
5759 do_stelem (&ctx, *ip, 0);
5760 ++ip;
5761 break;
5763 case CEE_LDELEM:
5764 code_bounds_check (5);
5765 do_ldelem (&ctx, *ip, read32 (ip + 1));
5766 ip += 5;
5767 break;
5769 case CEE_STELEM:
5770 code_bounds_check (5);
5771 do_stelem (&ctx, *ip, read32 (ip + 1));
5772 ip += 5;
5773 break;
5775 case CEE_UNBOX_ANY:
5776 code_bounds_check (5);
5777 do_unbox_any (&ctx, read32 (ip + 1));
5778 ip += 5;
5779 break;
5781 case CEE_CONV_OVF_I1:
5782 case CEE_CONV_OVF_U1:
5783 case CEE_CONV_OVF_I2:
5784 case CEE_CONV_OVF_U2:
5785 case CEE_CONV_OVF_I4:
5786 case CEE_CONV_OVF_U4:
5787 do_conversion (&ctx, TYPE_I4);
5788 ++ip;
5789 break;
5791 case CEE_CONV_OVF_I8:
5792 case CEE_CONV_OVF_U8:
5793 do_conversion (&ctx, TYPE_I8);
5794 ++ip;
5795 break;
5797 case CEE_CONV_OVF_I:
5798 case CEE_CONV_OVF_U:
5799 do_conversion (&ctx, TYPE_NATIVE_INT);
5800 ++ip;
5801 break;
5803 case CEE_REFANYVAL:
5804 code_bounds_check (5);
5805 do_refanyval (&ctx, read32 (ip + 1));
5806 ip += 5;
5807 break;
5809 case CEE_CKFINITE:
5810 do_ckfinite (&ctx);
5811 ++ip;
5812 break;
5814 case CEE_MKREFANY:
5815 code_bounds_check (5);
5816 do_mkrefany (&ctx, read32 (ip + 1));
5817 ip += 5;
5818 break;
5820 case CEE_LDTOKEN:
5821 code_bounds_check (5);
5822 do_load_token (&ctx, read32 (ip + 1));
5823 ip += 5;
5824 break;
5826 case CEE_ENDFINALLY:
5827 if (!is_correct_endfinally (ctx.header, ip_offset))
5828 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("endfinally must be used inside a finally/fault handler at 0x%04x", ctx.ip_offset));
5829 ctx.eval.size = 0;
5830 start = 1;
5831 ++ip;
5832 break;
5834 case CEE_LEAVE:
5835 code_bounds_check (5);
5836 do_leave (&ctx, read32 (ip + 1) + 5);
5837 ip += 5;
5838 start = 1;
5839 need_merge = 1;
5840 break;
5842 case CEE_LEAVE_S:
5843 code_bounds_check (2);
5844 do_leave (&ctx, (signed char)ip [1] + 2);
5845 ip += 2;
5846 start = 1;
5847 need_merge = 1;
5848 break;
5850 case CEE_PREFIX1:
5851 code_bounds_check (2);
5852 ++ip;
5853 switch (*ip) {
5854 case CEE_STLOC:
5855 code_bounds_check (3);
5856 store_local (&ctx, read16 (ip + 1));
5857 ip += 3;
5858 break;
5860 case CEE_CEQ:
5861 do_cmp_op (&ctx, cmp_br_eq_op, *ip);
5862 ++ip;
5863 break;
5865 case CEE_CGT:
5866 case CEE_CGT_UN:
5867 case CEE_CLT:
5868 case CEE_CLT_UN:
5869 do_cmp_op (&ctx, cmp_br_op, *ip);
5870 ++ip;
5871 break;
5873 case CEE_STARG:
5874 code_bounds_check (3);
5875 store_arg (&ctx, read16 (ip + 1) );
5876 ip += 3;
5877 break;
5880 case CEE_ARGLIST:
5881 if (!check_overflow (&ctx))
5882 break;
5883 if (ctx.signature->call_convention != MONO_CALL_VARARG)
5884 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot use arglist on method without VARGARG calling convention at 0x%04x", ctx.ip_offset));
5885 set_stack_value (&ctx, stack_push (&ctx), m_class_get_byval_arg (mono_defaults.argumenthandle_class), FALSE);
5886 ++ip;
5887 break;
5889 case CEE_LDFTN:
5890 code_bounds_check (5);
5891 do_load_function_ptr (&ctx, read32 (ip + 1), FALSE);
5892 ip += 5;
5893 break;
5895 case CEE_LDVIRTFTN:
5896 code_bounds_check (5);
5897 do_load_function_ptr (&ctx, read32 (ip + 1), TRUE);
5898 ip += 5;
5899 break;
5901 case CEE_LDARG:
5902 case CEE_LDARGA:
5903 code_bounds_check (3);
5904 push_arg (&ctx, read16 (ip + 1), *ip == CEE_LDARGA);
5905 ip += 3;
5906 break;
5908 case CEE_LDLOC:
5909 case CEE_LDLOCA:
5910 code_bounds_check (3);
5911 push_local (&ctx, read16 (ip + 1), *ip == CEE_LDLOCA);
5912 ip += 3;
5913 break;
5915 case CEE_LOCALLOC:
5916 do_localloc (&ctx);
5917 ++ip;
5918 break;
5920 case CEE_UNUSED56:
5921 case CEE_UNUSED57:
5922 case CEE_UNUSED70:
5923 case CEE_UNUSED:
5924 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5925 ++ip;
5926 break;
5927 case CEE_ENDFILTER:
5928 do_endfilter (&ctx);
5929 start = 1;
5930 ++ip;
5931 break;
5932 case CEE_UNALIGNED_:
5933 code_bounds_check (2);
5934 prefix |= PREFIX_UNALIGNED;
5935 ip += 2;
5936 break;
5937 case CEE_VOLATILE_:
5938 prefix |= PREFIX_VOLATILE;
5939 ++ip;
5940 break;
5941 case CEE_TAIL_:
5942 prefix |= PREFIX_TAIL;
5943 ++ip;
5944 if (ip < end && (*ip != CEE_CALL && *ip != CEE_CALLI && *ip != CEE_CALLVIRT))
5945 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("tail prefix must be used only with call opcodes at 0x%04x", ip_offset));
5946 break;
5948 case CEE_INITOBJ:
5949 code_bounds_check (5);
5950 do_initobj (&ctx, read32 (ip + 1));
5951 ip += 5;
5952 break;
5954 case CEE_CONSTRAINED_:
5955 code_bounds_check (5);
5956 ctx.constrained_type = get_boxable_mono_type (&ctx, read32 (ip + 1), "constrained.");
5957 prefix |= PREFIX_CONSTRAINED;
5958 ip += 5;
5959 break;
5961 case CEE_READONLY_:
5962 prefix |= PREFIX_READONLY;
5963 ip++;
5964 break;
5966 case CEE_CPBLK:
5967 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5968 if (!check_underflow (&ctx, 3))
5969 break;
5970 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction cpblk is not verifiable at 0x%04x", ctx.ip_offset));
5971 ip++;
5972 break;
5974 case CEE_INITBLK:
5975 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5976 if (!check_underflow (&ctx, 3))
5977 break;
5978 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction initblk is not verifiable at 0x%04x", ctx.ip_offset));
5979 ip++;
5980 break;
5982 case CEE_NO_:
5983 ip += 2;
5984 break;
5985 case CEE_RETHROW:
5986 if (!is_correct_rethrow (ctx.header, ip_offset))
5987 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("rethrow must be used inside a catch handler at 0x%04x", ctx.ip_offset));
5988 ctx.eval.size = 0;
5989 start = 1;
5990 ++ip;
5991 break;
5993 case CEE_SIZEOF:
5994 code_bounds_check (5);
5995 do_sizeof (&ctx, read32 (ip + 1));
5996 ip += 5;
5997 break;
5999 case CEE_REFANYTYPE:
6000 do_refanytype (&ctx);
6001 ++ip;
6002 break;
6004 default:
6005 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction FE %x at 0x%04x", *ip, ctx.ip_offset));
6006 ++ip;
6008 break;
6010 default:
6011 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ctx.ip_offset));
6012 ++ip;
6015 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
6016 if (prefix) {
6017 if (!ctx.prefix_set) //first prefix
6018 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
6019 ctx.prefix_set |= prefix;
6020 ctx.has_flags = TRUE;
6021 prefix = 0;
6022 } else {
6023 if (!ctx.has_flags)
6024 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
6026 if (ctx.prefix_set & PREFIX_CONSTRAINED)
6027 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after constrained prefix at 0x%04x", ctx.ip_offset));
6028 if (ctx.prefix_set & PREFIX_READONLY)
6029 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after readonly prefix at 0x%04x", ctx.ip_offset));
6030 if (ctx.prefix_set & PREFIX_VOLATILE)
6031 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after volatile prefix at 0x%04x", ctx.ip_offset));
6032 if (ctx.prefix_set & PREFIX_UNALIGNED)
6033 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after unaligned prefix at 0x%04x", ctx.ip_offset));
6034 ctx.prefix_set = prefix = 0;
6035 ctx.has_flags = FALSE;
6039 * if ip != end we overflowed: mark as error.
6041 if ((ip != end || !start) && ctx.verifiable && !ctx.list) {
6042 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Run ahead of method code at 0x%04x", ip_offset));
6045 /*We should guard against the last decoded opcode, otherwise we might add errors that doesn't make sense.*/
6046 for (i = 0; i < ctx.code_size && i < ip_offset; ++i) {
6047 if (ctx.code [i].flags & IL_CODE_FLAG_WAS_TARGET) {
6048 if (!(ctx.code [i].flags & IL_CODE_FLAG_SEEN))
6049 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or exception block target middle of instruction at 0x%04x", i));
6051 if (ctx.code [i].flags & IL_CODE_DELEGATE_SEQUENCE)
6052 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Branch to delegate code sequence at 0x%04x", i));
6054 if ((ctx.code [i].flags & IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL) && ctx.has_this_store)
6055 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at 0x%04x", i));
6057 if ((ctx.code [i].flags & IL_CODE_CALL_NONFINAL_VIRTUAL) && ctx.has_this_store)
6058 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));
6061 if (mono_method_is_constructor (ctx.method) && !ctx.super_ctor_called && !m_class_is_valuetype (ctx.method->klass) && ctx.method->klass != mono_defaults.object_class) {
6062 char *method_name = mono_method_full_name (ctx.method, TRUE);
6063 char *type = mono_type_get_full_name (ctx.method->klass);
6064 if (m_class_get_parent (ctx.method->klass) && mono_class_has_failure (m_class_get_parent (ctx.method->klass)))
6065 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));
6066 else
6067 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Constructor %s for type %s not calling base type ctor.", method_name, type));
6068 g_free (method_name);
6069 g_free (type);
6072 cleanup:
6073 if (ctx.code) {
6074 for (i = 0; i < ctx.header->code_size; ++i) {
6075 if (ctx.code [i].stack)
6076 g_free (ctx.code [i].stack);
6080 for (tmp = ctx.funptrs; tmp; tmp = tmp->next)
6081 g_free (tmp->data);
6082 g_slist_free (ctx.funptrs);
6084 for (tmp = ctx.exception_types; tmp; tmp = tmp->next)
6085 mono_metadata_free_type ((MonoType *)tmp->data);
6086 g_slist_free (ctx.exception_types);
6088 for (i = 0; i < ctx.num_locals; ++i) {
6089 if (ctx.locals [i])
6090 mono_metadata_free_type (ctx.locals [i]);
6092 for (i = 0; i < ctx.max_args; ++i) {
6093 if (ctx.params [i])
6094 mono_metadata_free_type (ctx.params [i]);
6097 if (ctx.eval.stack)
6098 g_free (ctx.eval.stack);
6099 if (ctx.code)
6100 g_free (ctx.code);
6101 g_free (ctx.locals);
6102 g_free (ctx.locals_verification_state);
6103 g_free (ctx.params);
6104 mono_basic_block_free (original_bb);
6105 mono_metadata_free_mh (ctx.header);
6107 finish_collect_stats ();
6108 return ctx.list;
6111 char*
6112 mono_verify_corlib ()
6114 /* This is a public API function so cannot be removed */
6115 return NULL;
6119 * mono_verifier_is_enabled_for_method:
6120 * \param method the method to probe
6121 * \returns TRUE if \p method needs to be verified.
6123 gboolean
6124 mono_verifier_is_enabled_for_method (MonoMethod *method)
6126 return mono_verifier_is_enabled_for_class (method->klass) && (method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD);
6130 * mono_verifier_is_enabled_for_class:
6131 * \param klass The \c MonoClass to probe
6132 * \returns TRUE if \p klass need to be verified.
6134 gboolean
6135 mono_verifier_is_enabled_for_class (MonoClass *klass)
6137 MonoImage *image = m_class_get_image (klass);
6138 return verify_all || (verifier_mode > MONO_VERIFIER_MODE_OFF && !(image->assembly && image->assembly->in_gac) && image != mono_defaults.corlib);
6141 gboolean
6142 mono_verifier_is_enabled_for_image (MonoImage *image)
6144 return verify_all || verifier_mode > MONO_VERIFIER_MODE_OFF;
6148 * Dynamic methods are not considered full trust since if the user is trusted and need to
6149 * generate unsafe code, make the method skip verification - this is a known good way to do it.
6151 gboolean
6152 mono_verifier_is_method_full_trust (MonoMethod *method)
6154 return mono_verifier_is_class_full_trust (method->klass) && !method_is_dynamic (method);
6158 * Returns if @klass is under full trust or not.
6160 * TODO This code doesn't take CAS into account.
6162 * Under verify_all all user code must be verifiable if no security option was set
6165 gboolean
6166 mono_verifier_is_class_full_trust (MonoClass *klass)
6168 MonoImage *image = m_class_get_image (klass);
6169 /* under CoreCLR code is trusted if it is part of the "platform" otherwise all code inside the GAC is trusted */
6170 gboolean trusted_location = !mono_security_core_clr_enabled () ?
6171 (image->assembly && image->assembly->in_gac) : mono_security_core_clr_is_platform_image (image);
6173 if (verify_all && verifier_mode == MONO_VERIFIER_MODE_OFF)
6174 return trusted_location || image == mono_defaults.corlib;
6175 return verifier_mode < MONO_VERIFIER_MODE_VERIFIABLE || trusted_location || image == mono_defaults.corlib;
6178 GSList*
6179 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility, gboolean is_fulltrust)
6181 return mono_method_verify (method,
6182 (verifier_mode != MONO_VERIFIER_MODE_STRICT ? MONO_VERIFY_NON_STRICT: 0)
6183 | (!is_fulltrust && !mono_verifier_is_method_full_trust (method) ? MONO_VERIFY_FAIL_FAST : 0)
6184 | (skip_visibility ? MONO_VERIFY_SKIP_VISIBILITY : 0));
6187 static int
6188 get_field_end (MonoClassField *field)
6190 int align;
6191 int size = mono_type_size (field->type, &align);
6192 if (size == 0)
6193 size = 4; /*FIXME Is this a safe bet?*/
6194 return size + field->offset;
6197 static gboolean
6198 verify_class_for_overlapping_reference_fields (MonoClass *klass)
6200 int i = 0, j;
6201 gpointer iter = NULL;
6202 MonoClassField *field;
6203 gboolean is_fulltrust = mono_verifier_is_class_full_trust (klass);
6204 /*We can't skip types with !has_references since this is calculated after we have run.*/
6205 if (!mono_class_is_explicit_layout (klass))
6206 return TRUE;
6209 /*We must check for stuff overlapping reference fields.
6210 The outer loop uses mono_class_get_fields_internal to ensure that MonoClass:fields get inited.
6212 while ((field = mono_class_get_fields_internal (klass, &iter))) {
6213 int fieldEnd = get_field_end (field);
6214 gboolean is_valuetype = !MONO_TYPE_IS_REFERENCE (field->type);
6215 ++i;
6217 if (mono_field_is_deleted (field) || (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
6218 continue;
6220 int fcount = mono_class_get_field_count (klass);
6221 MonoClassField *klass_fields = m_class_get_fields (klass);
6222 for (j = i; j < fcount; ++j) {
6223 MonoClassField *other = &klass_fields [j];
6224 int otherEnd = get_field_end (other);
6225 if (mono_field_is_deleted (other) || (is_valuetype && !MONO_TYPE_IS_REFERENCE (other->type)) || (other->type->attrs & FIELD_ATTRIBUTE_STATIC))
6226 continue;
6228 if (!is_valuetype && MONO_TYPE_IS_REFERENCE (other->type) && field->offset == other->offset && is_fulltrust)
6229 continue;
6231 if ((otherEnd > field->offset && otherEnd <= fieldEnd) || (other->offset >= field->offset && other->offset < fieldEnd))
6232 return FALSE;
6235 return TRUE;
6238 static guint
6239 field_hash (gconstpointer key)
6241 const MonoClassField *field = (const MonoClassField *)key;
6242 return g_str_hash (field->name) ^ mono_metadata_type_hash (field->type); /**/
6245 static gboolean
6246 field_equals (gconstpointer _a, gconstpointer _b)
6248 const MonoClassField *a = (const MonoClassField *)_a;
6249 const MonoClassField *b = (const MonoClassField *)_b;
6250 return !strcmp (a->name, b->name) && mono_metadata_type_equal (a->type, b->type);
6254 static gboolean
6255 verify_class_fields (MonoClass *klass)
6257 gpointer iter = NULL;
6258 MonoClassField *field;
6259 MonoGenericContext *context = mono_class_get_context (klass);
6260 GHashTable *unique_fields = g_hash_table_new_full (&field_hash, &field_equals, NULL, NULL);
6261 if (mono_class_is_gtd (klass))
6262 context = &mono_class_get_generic_container (klass)->context;
6264 while ((field = mono_class_get_fields_internal (klass, &iter)) != NULL) {
6265 if (!mono_type_is_valid_type_in_context (field->type, context)) {
6266 g_hash_table_destroy (unique_fields);
6267 return FALSE;
6269 if (g_hash_table_lookup (unique_fields, field)) {
6270 g_hash_table_destroy (unique_fields);
6271 return FALSE;
6273 g_hash_table_insert (unique_fields, field, field);
6275 g_hash_table_destroy (unique_fields);
6276 return TRUE;
6279 static gboolean
6280 verify_interfaces (MonoClass *klass)
6282 int i;
6283 guint16 klass_interface_count = m_class_get_interface_count (klass);
6284 MonoClass **klass_interfaces = m_class_get_interfaces (klass);
6285 for (i = 0; i < klass_interface_count; ++i) {
6286 MonoClass *iface = klass_interfaces [i];
6287 if (!mono_class_get_flags (iface))
6288 return FALSE;
6290 return TRUE;
6293 static gboolean
6294 verify_valuetype_layout_with_target (MonoClass *klass, MonoClass *target_class)
6296 int type;
6297 gpointer iter = NULL;
6298 MonoClassField *field;
6299 MonoClass *field_class;
6301 if (!m_class_is_valuetype (klass))
6302 return TRUE;
6304 type = m_class_get_byval_arg (klass)->type;
6305 /*primitive type fields are not properly decoded*/
6306 if ((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_R8) || (type >= MONO_TYPE_I && type <= MONO_TYPE_U))
6307 return TRUE;
6309 while ((field = mono_class_get_fields_internal (klass, &iter)) != NULL) {
6310 if (!field->type)
6311 return FALSE;
6313 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
6314 continue;
6316 field_class = mono_class_get_generic_type_definition (mono_class_from_mono_type (field->type));
6318 if (field_class == target_class || klass == field_class || !verify_valuetype_layout_with_target (field_class, target_class))
6319 return FALSE;
6322 return TRUE;
6325 static gboolean
6326 verify_valuetype_layout (MonoClass *klass)
6328 gboolean res;
6329 res = verify_valuetype_layout_with_target (klass, klass);
6330 return res;
6333 static gboolean
6334 recursive_mark_constraint_args (MonoBitSet *used_args, MonoGenericContainer *gc, MonoType *type)
6336 int idx;
6337 MonoClass **constraints;
6338 MonoGenericParamInfo *param_info;
6340 g_assert (mono_type_is_generic_argument (type));
6342 idx = mono_type_get_generic_param_num (type);
6343 if (mono_bitset_test_fast (used_args, idx))
6344 return FALSE;
6346 mono_bitset_set_fast (used_args, idx);
6347 param_info = mono_generic_container_get_param_info (gc, idx);
6349 if (!param_info->constraints)
6350 return TRUE;
6352 for (constraints = param_info->constraints; *constraints; ++constraints) {
6353 MonoClass *ctr = *constraints;
6354 MonoType *constraint_type = m_class_get_byval_arg (ctr);
6356 if (mono_type_is_generic_argument (constraint_type) && !recursive_mark_constraint_args (used_args, gc, constraint_type))
6357 return FALSE;
6359 return TRUE;
6362 static gboolean
6363 verify_generic_parameters (MonoClass *klass)
6365 int i;
6366 MonoGenericContainer *gc = mono_class_get_generic_container (klass);
6367 MonoBitSet *used_args = mono_bitset_new (gc->type_argc, 0);
6369 for (i = 0; i < gc->type_argc; ++i) {
6370 MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
6371 MonoClass **constraints;
6373 if (!param_info->constraints)
6374 continue;
6376 mono_bitset_clear_all (used_args);
6377 mono_bitset_set_fast (used_args, i);
6379 for (constraints = param_info->constraints; *constraints; ++constraints) {
6380 MonoClass *ctr = *constraints;
6381 MonoType *constraint_type = m_class_get_byval_arg (ctr);
6383 if (!mono_class_can_access_class (klass, ctr))
6384 goto fail;
6386 if (!mono_type_is_valid_type_in_context (constraint_type, &gc->context))
6387 goto fail;
6389 if (mono_type_is_generic_argument (constraint_type) && !recursive_mark_constraint_args (used_args, gc, constraint_type))
6390 goto fail;
6391 if (mono_class_is_ginst (ctr) && !mono_class_is_valid_generic_instantiation (NULL, ctr))
6392 goto fail;
6395 mono_bitset_free (used_args);
6396 return TRUE;
6398 fail:
6399 mono_bitset_free (used_args);
6400 return FALSE;
6404 * Check if the class is verifiable.
6406 * Right now there are no conditions that make a class a valid but not verifiable. Both overlapping reference
6407 * field and invalid generic instantiation are fatal errors.
6409 * This method must be safe to be called from mono_class_init and all code must be carefull about that.
6412 gboolean
6413 mono_verifier_verify_class (MonoClass *klass)
6415 MonoClass *klass_parent = m_class_get_parent (klass);
6416 /*Neither <Module>, object or ifaces have parent.*/
6417 if (!klass_parent &&
6418 klass != mono_defaults.object_class &&
6419 !MONO_CLASS_IS_INTERFACE (klass) &&
6420 (!image_is_dynamic (m_class_get_image (klass)) && m_class_get_type_token (klass) != 0x2000001)) /*<Module> is the first type in the assembly*/
6421 return FALSE;
6422 if (m_class_get_parent (klass)) {
6423 if (MONO_CLASS_IS_INTERFACE (klass_parent))
6424 return FALSE;
6425 if (!mono_class_is_ginst (klass) && mono_class_is_gtd (klass_parent))
6426 return FALSE;
6427 if (mono_class_is_ginst (klass_parent) && !mono_class_is_ginst (klass)) {
6428 MonoGenericContext *context = mono_class_get_context (klass);
6429 if (mono_class_is_gtd (klass))
6430 context = &mono_class_get_generic_container (klass)->context;
6431 if (!mono_type_is_valid_type_in_context (m_class_get_byval_arg (klass_parent), context))
6432 return FALSE;
6435 if (mono_class_is_gtd (klass) && (mono_class_is_explicit_layout (klass)))
6436 return FALSE;
6437 if (mono_class_is_gtd (klass) && !verify_generic_parameters (klass))
6438 return FALSE;
6439 if (!verify_class_for_overlapping_reference_fields (klass))
6440 return FALSE;
6441 if (mono_class_is_ginst (klass) && !mono_class_is_valid_generic_instantiation (NULL, klass))
6442 return FALSE;
6443 if (!mono_class_is_ginst (klass) && !verify_class_fields (klass))
6444 return FALSE;
6445 if (m_class_is_valuetype (klass) && !verify_valuetype_layout (klass))
6446 return FALSE;
6447 if (!verify_interfaces (klass))
6448 return FALSE;
6449 return TRUE;
6452 gboolean
6453 mono_verifier_class_is_valid_generic_instantiation (MonoClass *klass)
6455 return mono_class_is_valid_generic_instantiation (NULL, klass);
6458 gboolean
6459 mono_verifier_is_method_valid_generic_instantiation (MonoMethod *method)
6461 if (!method->is_inflated)
6462 return TRUE;
6463 return mono_method_is_valid_generic_instantiation (NULL, method);
6466 #else
6468 gboolean
6469 mono_verifier_verify_class (MonoClass *klass)
6471 /* The verifier was disabled at compile time */
6472 return TRUE;
6475 GSList*
6476 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility, gboolean is_fulltrust)
6478 /* The verifier was disabled at compile time */
6479 return NULL;
6482 gboolean
6483 mono_verifier_is_class_full_trust (MonoClass *klass)
6485 /* The verifier was disabled at compile time */
6486 return TRUE;
6489 gboolean
6490 mono_verifier_is_method_full_trust (MonoMethod *method)
6492 /* The verifier was disabled at compile time */
6493 return TRUE;
6496 gboolean
6497 mono_verifier_is_enabled_for_image (MonoImage *image)
6499 /* The verifier was disabled at compile time */
6500 return FALSE;
6503 gboolean
6504 mono_verifier_is_enabled_for_class (MonoClass *klass)
6506 /* The verifier was disabled at compile time */
6507 return FALSE;
6510 gboolean
6511 mono_verifier_is_enabled_for_method (MonoMethod *method)
6513 /* The verifier was disabled at compile time */
6514 return FALSE;
6517 GSList*
6518 mono_method_verify (MonoMethod *method, int level)
6520 /* The verifier was disabled at compile time */
6521 return NULL;
6524 void
6525 mono_free_verify_list (GSList *list)
6527 /* The verifier was disabled at compile time */
6528 /* will always be null if verifier is disabled */
6531 gboolean
6532 mono_verifier_class_is_valid_generic_instantiation (MonoClass *klass)
6534 return TRUE;
6537 gboolean
6538 mono_verifier_is_method_valid_generic_instantiation (MonoMethod *method)
6540 return TRUE;
6545 #endif