remove GenericVectorTests from rsp (#17366)
[mono-project.git] / mono / metadata / verify.c
blob768de3da9de6f0413e202628dab49667d09c2d5d
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;
41 #define CTOR_REQUIRED_FLAGS (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_RT_SPECIAL_NAME)
42 #define CTOR_INVALID_FLAGS (METHOD_ATTRIBUTE_STATIC)
45 * Set the desired level of checks for the verfier.
48 void
49 mono_verifier_set_mode (MiniVerifierMode mode)
51 verifier_mode = mode;
54 void
55 mono_verifier_enable_verify_all ()
57 verify_all = TRUE;
60 static gboolean
61 mono_method_is_constructor (MonoMethod *method)
63 return ((method->flags & CTOR_REQUIRED_FLAGS) == CTOR_REQUIRED_FLAGS &&
64 !(method->flags & CTOR_INVALID_FLAGS) &&
65 !strcmp (".ctor", method->name));
68 static gboolean
69 mono_class_has_default_constructor (MonoClass *klass)
71 MonoMethod *method;
72 int i;
74 mono_class_setup_methods (klass);
75 if (mono_class_has_failure (klass))
76 return FALSE;
78 int mcount = mono_class_get_method_count (klass);
79 MonoMethod **klass_methods = m_class_get_methods (klass);
80 for (i = 0; i < mcount; ++i) {
81 method = klass_methods [i];
82 if (mono_method_is_constructor (method) &&
83 mono_method_signature_internal (method) &&
84 mono_method_signature_internal (method)->param_count == 0 &&
85 (method->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC)
86 return TRUE;
88 return FALSE;
92 * Returns TURE if @type is VAR or MVAR
94 static gboolean
95 mono_type_is_generic_argument (MonoType *type)
97 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
100 /*A side note here. We don't need to check if arguments are broken since this
101 is only need to be done by the runtime before realizing the type.
103 static gboolean
104 is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
106 ERROR_DECL (error);
107 int i;
109 if (ginst->type_argc != gc->type_argc)
110 return FALSE;
112 for (i = 0; i < gc->type_argc; ++i) {
113 MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
114 MonoClass *paramClass;
115 MonoClass **constraints;
116 MonoType *param_type = ginst->type_argv [i];
118 /*it's not our job to validate type variables*/
119 if (mono_type_is_generic_argument (param_type))
120 continue;
122 paramClass = mono_class_from_mono_type_internal (param_type);
125 /* A GTD can't be a generic argument.
127 * Due to how types are encoded we must check for the case of a genericinst MonoType and GTD MonoClass.
128 * This happens in cases such as: class Foo<T> { void X() { new Bar<T> (); } }
130 * Open instantiations can have GTDs as this happens when one type is instantiated with others params
131 * and the former has an expansion into the later. For example:
132 * class B<K> {}
133 * class A<T>: B<K> {}
134 * The type A <K> has a parent B<K>, that is inflated into the GTD B<>.
135 * Since A<K> is open, thus not instantiatable, this is valid.
137 if (mono_class_is_gtd (paramClass) && param_type->type != MONO_TYPE_GENERICINST && !ginst->is_open)
138 return FALSE;
140 /*it's not safe to call mono_class_init_internal from here*/
141 if (mono_class_is_ginst (paramClass) && !m_class_is_inited (paramClass)) {
142 if (!mono_verifier_class_is_valid_generic_instantiation (paramClass))
143 return FALSE;
146 if (!param_info->constraints && !(param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK))
147 continue;
149 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && (!m_class_is_valuetype (paramClass) || mono_class_is_nullable (paramClass)))
150 return FALSE;
152 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && m_class_is_valuetype (paramClass))
153 return FALSE;
155 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !m_class_is_valuetype (paramClass) && !mono_class_has_default_constructor (paramClass))
156 return FALSE;
158 if (!param_info->constraints)
159 continue;
161 for (constraints = param_info->constraints; *constraints; ++constraints) {
162 MonoClass *ctr = *constraints;
163 MonoType *inflated;
165 inflated = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (ctr), context, error);
166 if (!is_ok (error)) {
167 mono_error_cleanup (error);
168 return FALSE;
170 ctr = mono_class_from_mono_type_internal (inflated);
171 mono_metadata_free_type (inflated);
173 /*FIXME maybe we need the same this as verifier_class_is_assignable_from*/
174 if (!mono_class_is_assignable_from_slow (ctr, paramClass))
175 return FALSE;
178 return TRUE;
181 gboolean
182 mono_verifier_class_is_valid_generic_instantiation (MonoClass *klass)
184 MonoGenericClass *gklass = mono_class_get_generic_class (klass);
185 MonoGenericInst *ginst = gklass->context.class_inst;
186 MonoGenericContainer *gc = mono_class_get_generic_container (gklass->container_class);
187 return is_valid_generic_instantiation (gc, &gklass->context, ginst);
190 gboolean
191 mono_verifier_is_method_valid_generic_instantiation (MonoMethod *method)
193 if (!method->is_inflated)
194 return TRUE;
195 MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
196 MonoGenericInst *ginst = gmethod->context.method_inst;
197 MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
198 if (!gc) /*non-generic inflated method - it's part of a generic type */
199 return TRUE;
200 return is_valid_generic_instantiation (gc, &gmethod->context, ginst);
203 #ifndef DISABLE_VERIFIER
205 * Pull the list of opcodes
207 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
208 a = i,
210 enum {
211 #include "mono/cil/opcode.def"
212 LAST = 0xff
214 #undef OPDEF
216 #ifdef MONO_VERIFIER_DEBUG
217 #define VERIFIER_DEBUG(code) do { code } while (0)
218 #else
219 #define VERIFIER_DEBUG(code)
220 #endif
222 //////////////////////////////////////////////////////////////////
223 #define IS_STRICT_MODE(ctx) (((ctx)->level & MONO_VERIFY_NON_STRICT) == 0)
224 #define IS_FAIL_FAST_MODE(ctx) (((ctx)->level & MONO_VERIFY_FAIL_FAST) == MONO_VERIFY_FAIL_FAST)
225 #define IS_SKIP_VISIBILITY(ctx) (((ctx)->level & MONO_VERIFY_SKIP_VISIBILITY) == MONO_VERIFY_SKIP_VISIBILITY)
226 #define IS_REPORT_ALL_ERRORS(ctx) (((ctx)->level & MONO_VERIFY_REPORT_ALL_ERRORS) == MONO_VERIFY_REPORT_ALL_ERRORS)
227 #define CLEAR_PREFIX(ctx, prefix) do { (ctx)->prefix_set &= ~(prefix); } while (0)
228 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
229 do { \
230 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
231 vinfo->info.status = __status; \
232 vinfo->info.message = ( __msg ); \
233 vinfo->exception_type = (__exception); \
234 (__ctx)->list = g_slist_prepend ((__ctx)->list, vinfo); \
235 } while (0)
237 //TODO support MONO_VERIFY_REPORT_ALL_ERRORS
238 #define ADD_VERIFY_ERROR(__ctx, __msg) \
239 do { \
240 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
241 (__ctx)->valid = 0; \
242 } while (0)
244 #define CODE_NOT_VERIFIABLE(__ctx, __msg) \
245 do { \
246 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
247 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, MONO_EXCEPTION_UNVERIFIABLE_IL); \
248 (__ctx)->verifiable = 0; \
249 if (IS_FAIL_FAST_MODE (__ctx)) \
250 (__ctx)->valid = 0; \
252 } while (0)
254 #define ADD_VERIFY_ERROR2(__ctx, __msg, __exception) \
255 do { \
256 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, __exception); \
257 (__ctx)->valid = 0; \
258 } while (0)
260 #define CODE_NOT_VERIFIABLE2(__ctx, __msg, __exception) \
261 do { \
262 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
263 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, __exception); \
264 (__ctx)->verifiable = 0; \
265 if (IS_FAIL_FAST_MODE (__ctx)) \
266 (__ctx)->valid = 0; \
268 } while (0)
270 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
271 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
273 #if SIZEOF_VOID_P == 4
274 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
275 #else
276 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
277 #endif
279 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
280 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
282 /*Flags to be used with ILCodeDesc::flags */
283 enum {
284 /*Instruction has not been processed.*/
285 IL_CODE_FLAG_NOT_PROCESSED = 0,
286 /*Instruction was decoded by mono_method_verify loop.*/
287 IL_CODE_FLAG_SEEN = 1,
288 /*Instruction was target of a branch or is at a protected block boundary.*/
289 IL_CODE_FLAG_WAS_TARGET = 2,
290 /*Used by stack_init to avoid double initialize each entry.*/
291 IL_CODE_FLAG_STACK_INITED = 4,
292 /*Used by merge_stacks to decide if it should just copy the eval stack.*/
293 IL_CODE_STACK_MERGED = 8,
294 /*This instruction is part of the delegate construction sequence, it cannot be target of a branch.*/
295 IL_CODE_DELEGATE_SEQUENCE = 0x10,
296 /*This is a delegate created from a ldftn to a non final virtual method*/
297 IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL = 0x20,
298 /*This is a call to a non final virtual method*/
299 IL_CODE_CALL_NONFINAL_VIRTUAL = 0x40,
302 typedef enum {
303 RESULT_VALID,
304 RESULT_UNVERIFIABLE,
305 RESULT_INVALID
306 } verify_result_t;
308 typedef struct {
309 MonoType *type;
310 int stype;
311 MonoMethod *method;
312 } ILStackDesc;
315 typedef struct {
316 ILStackDesc *stack;
317 guint16 size, max_size;
318 guint16 flags;
319 } ILCodeDesc;
321 typedef struct {
322 int max_args;
323 int max_stack;
324 int verifiable;
325 int valid;
326 int level;
328 int code_size;
329 ILCodeDesc *code;
330 ILCodeDesc eval;
332 MonoType **params;
333 GSList *list;
334 /*Allocated fnptr MonoType that should be freed by us.*/
335 GSList *funptrs;
336 /*Type dup'ed exception types from catch blocks.*/
337 GSList *exception_types;
339 int num_locals;
340 MonoType **locals;
341 char *locals_verification_state;
343 /*TODO get rid of target here, need_merge in mono_method_verify and hoist the merging code in the branching code*/
344 int target;
346 guint32 ip_offset;
347 MonoMethodSignature *signature;
348 MonoMethodHeader *header;
350 MonoGenericContext *generic_context;
351 MonoImage *image;
352 MonoMethod *method;
354 /*This flag helps solving a corner case of delegate verification in that you cannot have a "starg 0"
355 *on a method that creates a delegate for a non-final virtual method using ldftn*/
356 gboolean has_this_store;
358 /*This flag is used to control if the contructor of the parent class has been called.
359 *If the this pointer is pushed on the eval stack and it's a reference type constructor and
360 * super_ctor_called is false, the uninitialized flag is set on the pushed value.
362 * Poping an uninitialized this ptr from the eval stack is an unverifiable operation unless
363 * the safe variant is used. Only a few opcodes can use it : dup, pop, ldfld, stfld and call to a constructor.
365 gboolean super_ctor_called;
367 guint32 prefix_set;
368 gboolean has_flags;
369 MonoType *constrained_type;
370 } VerifyContext;
372 static void
373 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external);
375 static int
376 get_stack_type (MonoType *type);
378 static gboolean
379 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn);
381 static gboolean
382 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass);
384 static gboolean
385 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method);
387 static MonoGenericParam*
388 verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type);
390 static gboolean
391 verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate);
392 //////////////////////////////////////////////////////////////////
396 enum {
397 TYPE_INV = 0, /* leave at 0. */
398 TYPE_I4 = 1,
399 TYPE_I8 = 2,
400 TYPE_NATIVE_INT = 3,
401 TYPE_R8 = 4,
402 /* Used by operator tables to resolve pointer types (managed & unmanaged) and by unmanaged pointer types*/
403 TYPE_PTR = 5,
404 /* value types and classes */
405 TYPE_COMPLEX = 6,
406 /* Number of types, used to define the size of the tables*/
407 TYPE_MAX = 6,
409 /* Used by tables to signal that a result is not verifiable*/
410 NON_VERIFIABLE_RESULT = 0x80,
412 /*Mask used to extract just the type, excluding flags */
413 TYPE_MASK = 0x0F,
415 /* The stack type is a managed pointer, unmask the value to res */
416 POINTER_MASK = 0x100,
418 /*Stack type with the pointer mask*/
419 RAW_TYPE_MASK = 0x10F,
421 /* Controlled Mutability Manager Pointer */
422 CMMP_MASK = 0x200,
424 /* The stack type is a null literal*/
425 NULL_LITERAL_MASK = 0x400,
427 /**Used by ldarg.0 and family to let delegate verification happens.*/
428 THIS_POINTER_MASK = 0x800,
430 /**Signals that this is a boxed value type*/
431 BOXED_MASK = 0x1000,
433 /*This is an unitialized this ref*/
434 UNINIT_THIS_MASK = 0x2000,
436 /* This is a safe to return byref */
437 SAFE_BYREF_MASK = 0x4000,
440 static const char* const
441 type_names [TYPE_MAX + 1] = {
442 "Invalid",
443 "Int32",
444 "Int64",
445 "Native Int",
446 "Float64",
447 "Native Pointer",
448 "Complex"
451 enum {
452 PREFIX_UNALIGNED = 1,
453 PREFIX_VOLATILE = 2,
454 PREFIX_TAIL = 4,
455 PREFIX_CONSTRAINED = 8,
456 PREFIX_READONLY = 16
458 //////////////////////////////////////////////////////////////////
460 #ifdef ENABLE_VERIFIER_STATS
462 #define _MEM_ALLOC(amt) do { allocated_memory += (amt); working_set += (amt); } while (0)
463 #define _MEM_FREE(amt) do { working_set -= (amt); } while (0)
465 static int allocated_memory;
466 static int working_set;
467 static int max_allocated_memory;
468 static int max_working_set;
469 static int total_allocated_memory;
471 static void
472 finish_collect_stats (void)
474 max_allocated_memory = MAX (max_allocated_memory, allocated_memory);
475 max_working_set = MAX (max_working_set, working_set);
476 total_allocated_memory += allocated_memory;
477 allocated_memory = working_set = 0;
480 static void
481 init_verifier_stats (void)
483 static gboolean inited;
484 if (!inited) {
485 inited = TRUE;
486 mono_counters_register ("Maximum memory allocated during verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &max_allocated_memory);
487 mono_counters_register ("Maximum memory used during verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &max_working_set);
488 mono_counters_register ("Total memory allocated for verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &total_allocated_memory);
492 #else
494 #define _MEM_ALLOC(amt) do {} while (0)
495 #define _MEM_FREE(amt) do { } while (0)
497 #define finish_collect_stats()
498 #define init_verifier_stats()
500 #endif
503 //////////////////////////////////////////////////////////////////
506 * Verify if @token refers to a valid row on int's table.
508 static gboolean
509 token_bounds_check (MonoImage *image, guint32 token)
511 if (image_is_dynamic (image))
512 return mono_dynamic_image_is_valid_token ((MonoDynamicImage*)image, token);
513 return image->tables [mono_metadata_token_table (token)].rows >= mono_metadata_token_index (token) && mono_metadata_token_index (token) > 0;
516 static MonoType *
517 mono_type_create_fnptr_from_mono_method (VerifyContext *ctx, MonoMethod *method)
519 MonoType *res = g_new0 (MonoType, 1);
520 _MEM_ALLOC (sizeof (MonoType));
522 //FIXME use mono_method_get_signature_full
523 res->data.method = mono_method_signature_internal (method);
524 res->type = MONO_TYPE_FNPTR;
525 ctx->funptrs = g_slist_prepend (ctx->funptrs, res);
526 return res;
530 * mono_type_is_enum_type:
532 * Returns: TRUE if @type is an enum type.
534 static gboolean
535 mono_type_is_enum_type (MonoType *type)
537 if (type->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (type->data.klass))
538 return TRUE;
539 if (type->type == MONO_TYPE_GENERICINST && m_class_is_enumtype (type->data.generic_class->container_class))
540 return TRUE;
541 return FALSE;
545 * mono_type_is_value_type:
547 * Returns: TRUE if @type is named after @namespace.@name.
550 static gboolean
551 mono_type_is_value_type (MonoType *type, const char *namespace_, const char *name)
553 return type->type == MONO_TYPE_VALUETYPE &&
554 !strcmp (namespace_, m_class_get_name_space (type->data.klass)) &&
555 !strcmp (name, m_class_get_name (type->data.klass));
559 * mono_type_get_underlying_type_any:
561 * This functions is just like mono_type_get_underlying_type but it doesn't care if the type is byref.
563 * Returns the underlying type of @type regardless if it is byref or not.
565 static MonoType*
566 mono_type_get_underlying_type_any (MonoType *type)
568 if (type->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (type->data.klass))
569 return mono_class_enum_basetype_internal (type->data.klass);
570 if (type->type == MONO_TYPE_GENERICINST && m_class_is_enumtype (type->data.generic_class->container_class))
571 return mono_class_enum_basetype_internal (type->data.generic_class->container_class);
572 return type;
575 static G_GNUC_UNUSED const char*
576 mono_type_get_stack_name (MonoType *type)
578 return type_names [get_stack_type (type) & TYPE_MASK];
582 * Verify if @type is valid for the given @ctx verification context.
583 * this function checks for VAR and MVAR types that are invalid under the current verifier,
585 static gboolean
586 mono_type_is_valid_type_in_context_full (MonoType *type, MonoGenericContext *context, gboolean check_gtd)
588 int i;
589 MonoGenericInst *inst;
591 switch (type->type) {
592 case MONO_TYPE_VAR:
593 case MONO_TYPE_MVAR:
594 if (!context)
595 return FALSE;
596 inst = type->type == MONO_TYPE_VAR ? context->class_inst : context->method_inst;
597 if (!inst || mono_type_get_generic_param_num (type) >= inst->type_argc)
598 return FALSE;
599 break;
600 case MONO_TYPE_SZARRAY:
601 return mono_type_is_valid_type_in_context_full (m_class_get_byval_arg (type->data.klass), context, check_gtd);
602 case MONO_TYPE_ARRAY:
603 return mono_type_is_valid_type_in_context_full (m_class_get_byval_arg (type->data.array->eklass), context, check_gtd);
604 case MONO_TYPE_PTR:
605 return mono_type_is_valid_type_in_context_full (type->data.type, context, check_gtd);
606 case MONO_TYPE_GENERICINST:
607 inst = type->data.generic_class->context.class_inst;
608 if (!inst->is_open)
609 break;
610 for (i = 0; i < inst->type_argc; ++i)
611 if (!mono_type_is_valid_type_in_context_full (inst->type_argv [i], context, check_gtd))
612 return FALSE;
613 break;
614 case MONO_TYPE_CLASS:
615 case MONO_TYPE_VALUETYPE: {
616 MonoClass *klass = type->data.klass;
617 MonoType *klass_byval_arg = m_class_get_byval_arg (klass);
619 * It's possible to encode generic'sh types in such a way that they disguise themselves as class or valuetype.
620 * Fixing the type decoding is really tricky since under some cases this behavior is needed, for example, to
621 * have a 'class' type pointing to a 'genericinst' class.
623 * For the runtime these non canonical (weird) encodings work fine, the worst they can cause is some
624 * reflection oddities which are harmless - to security at least.
626 if (klass_byval_arg->type != type->type)
627 return mono_type_is_valid_type_in_context_full (klass_byval_arg, context, check_gtd);
629 if (check_gtd && mono_class_is_gtd (klass))
630 return FALSE;
631 break;
633 default:
634 break;
636 return TRUE;
639 static gboolean
640 mono_type_is_valid_type_in_context (MonoType *type, MonoGenericContext *context)
642 return mono_type_is_valid_type_in_context_full (type, context, FALSE);
645 /*This function returns NULL if the type is not instantiatable*/
646 static MonoType*
647 verifier_inflate_type (VerifyContext *ctx, MonoType *type, MonoGenericContext *context)
649 ERROR_DECL (error);
650 MonoType *result;
652 result = mono_class_inflate_generic_type_checked (type, context, error);
653 if (!is_ok (error)) {
654 mono_error_cleanup (error);
655 return NULL;
657 return result;
661 * mono_generic_param_is_constraint_compatible:
663 * \returns TRUE if \p candidate is constraint compatible with \p target.
665 * This means that \p candidate constraints are a super set of \p target constaints
667 static gboolean
668 mono_generic_param_is_constraint_compatible (VerifyContext *ctx, MonoGenericParam *target, MonoGenericParam *candidate, MonoClass *candidate_param_class, MonoGenericContext *context)
670 MonoGenericParamInfo *tinfo = mono_generic_param_info (target);
671 MonoGenericParamInfo *cinfo = mono_generic_param_info (candidate);
672 MonoClass **candidate_class;
673 gboolean class_constraint_satisfied = FALSE;
674 gboolean valuetype_constraint_satisfied = FALSE;
676 int tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
677 int cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
679 if (cinfo->constraints) {
680 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
681 MonoClass *cc;
682 MonoType *inflated = verifier_inflate_type (ctx, m_class_get_byval_arg (*candidate_class), ctx->generic_context);
683 if (!inflated)
684 return FALSE;
685 cc = mono_class_from_mono_type_internal (inflated);
686 mono_metadata_free_type (inflated);
688 if (mono_type_is_reference (m_class_get_byval_arg (cc)) && !MONO_CLASS_IS_INTERFACE_INTERNAL (cc))
689 class_constraint_satisfied = TRUE;
690 else if (!mono_type_is_reference (m_class_get_byval_arg (cc)) && !MONO_CLASS_IS_INTERFACE_INTERNAL (cc))
691 valuetype_constraint_satisfied = TRUE;
694 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
695 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
697 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
698 return FALSE;
699 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
700 return FALSE;
701 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
702 valuetype_constraint_satisfied)) {
703 return FALSE;
707 if (tinfo->constraints) {
708 MonoClass **target_class;
709 for (target_class = tinfo->constraints; *target_class; ++target_class) {
710 MonoClass *tc;
711 MonoType *inflated = verifier_inflate_type (ctx, m_class_get_byval_arg (*target_class), context);
712 if (!inflated)
713 return FALSE;
714 tc = mono_class_from_mono_type_internal (inflated);
715 mono_metadata_free_type (inflated);
718 * A constraint from @target might inflate into @candidate itself and in that case we don't need
719 * check it's constraints since it satisfy the constraint by itself.
721 if (mono_metadata_type_equal (m_class_get_byval_arg (tc), m_class_get_byval_arg (candidate_param_class)))
722 continue;
724 if (!cinfo->constraints)
725 return FALSE;
727 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
728 MonoClass *cc;
729 inflated = verifier_inflate_type (ctx, m_class_get_byval_arg (*candidate_class), ctx->generic_context);
730 if (!inflated)
731 return FALSE;
732 cc = mono_class_from_mono_type_internal (inflated);
733 mono_metadata_free_type (inflated);
735 if (verifier_class_is_assignable_from (tc, cc))
736 break;
739 * This happens when we have the following:
741 * Bar<K> where K : IFace
742 * Foo<T, U> where T : U where U : IFace
743 * ...
744 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
747 if (mono_type_is_generic_argument (m_class_get_byval_arg (cc))) {
748 MonoGenericParam *other_candidate = verifier_get_generic_param_from_type (ctx, m_class_get_byval_arg (cc));
750 if (mono_generic_param_is_constraint_compatible (ctx, target, other_candidate, cc, context)) {
751 break;
755 if (!*candidate_class)
756 return FALSE;
759 return TRUE;
762 static MonoGenericParam*
763 verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type)
765 MonoGenericContainer *gc;
766 MonoMethod *method = ctx->method;
767 int num;
769 num = mono_type_get_generic_param_num (type);
771 if (type->type == MONO_TYPE_VAR) {
772 MonoClass *gtd = method->klass;
773 if (mono_class_is_ginst (gtd))
774 gtd = mono_class_get_generic_class (gtd)->container_class;
775 gc = mono_class_try_get_generic_container (gtd);
776 } else { //MVAR
777 MonoMethod *gmd = method;
778 if (method->is_inflated)
779 gmd = ((MonoMethodInflated*)method)->declaring;
780 gc = mono_method_get_generic_container (gmd);
782 if (!gc)
783 return NULL;
784 return mono_generic_container_get_param (gc, num);
790 * Verify if @type is valid for the given @ctx verification context.
791 * this function checks for VAR and MVAR types that are invalid under the current verifier,
792 * This means that it either
794 static gboolean
795 is_valid_type_in_context (VerifyContext *ctx, MonoType *type)
797 return mono_type_is_valid_type_in_context (type, ctx->generic_context);
800 static gboolean
801 is_valid_generic_instantiation_in_context (VerifyContext *ctx, MonoGenericInst *ginst, gboolean check_gtd)
803 int i;
804 for (i = 0; i < ginst->type_argc; ++i) {
805 MonoType *type = ginst->type_argv [i];
807 if (!mono_type_is_valid_type_in_context_full (type, ctx->generic_context, TRUE))
808 return FALSE;
810 return TRUE;
813 static gboolean
814 generic_arguments_respect_constraints (VerifyContext *ctx, MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
816 int i;
817 for (i = 0; i < ginst->type_argc; ++i) {
818 MonoType *type = ginst->type_argv [i];
819 MonoGenericParam *target = mono_generic_container_get_param (gc, i);
820 MonoGenericParam *candidate;
821 MonoClass *candidate_class;
823 if (!mono_type_is_generic_argument (type))
824 continue;
826 if (!is_valid_type_in_context (ctx, type))
827 return FALSE;
829 candidate = verifier_get_generic_param_from_type (ctx, type);
830 candidate_class = mono_class_from_mono_type_internal (type);
832 if (!mono_generic_param_is_constraint_compatible (ctx, target, candidate, candidate_class, context))
833 return FALSE;
835 return TRUE;
838 static gboolean
839 mono_method_repect_method_constraints (VerifyContext *ctx, MonoMethod *method)
841 MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
842 MonoGenericInst *ginst = gmethod->context.method_inst;
843 MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
844 return !gc || generic_arguments_respect_constraints (ctx, gc, &gmethod->context, ginst);
847 static gboolean
848 mono_class_repect_method_constraints (VerifyContext *ctx, MonoClass *klass)
850 MonoGenericClass *gklass = mono_class_get_generic_class (klass);
851 MonoGenericInst *ginst = gklass->context.class_inst;
852 MonoGenericContainer *gc = mono_class_get_generic_container (gklass->container_class);
853 return !gc || generic_arguments_respect_constraints (ctx, gc, &gklass->context, ginst);
856 static gboolean
857 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method)
859 MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
860 MonoGenericInst *ginst = gmethod->context.method_inst;
861 MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
862 if (!gc) /*non-generic inflated method - it's part of a generic type */
863 return TRUE;
864 if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst, TRUE))
865 return FALSE;
866 return is_valid_generic_instantiation (gc, &gmethod->context, ginst);
869 static gboolean
870 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass)
872 MonoGenericClass *gklass = mono_class_get_generic_class (klass);
873 MonoGenericInst *ginst = gklass->context.class_inst;
874 MonoGenericContainer *gc = mono_class_get_generic_container (gklass->container_class);
875 if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst, TRUE))
876 return FALSE;
877 return is_valid_generic_instantiation (gc, &gklass->context, ginst);
880 static gboolean
881 mono_type_is_valid_in_context (VerifyContext *ctx, MonoType *type)
883 MonoClass *klass;
885 if (type == NULL) {
886 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid null type at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
887 return FALSE;
890 if (!is_valid_type_in_context (ctx, type)) {
891 char *str = mono_type_full_name (type);
892 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type (%s%s) (argument out of range or %s is not generic) at 0x%04x",
893 str [0] == '!' ? "" : type->type == MONO_TYPE_VAR ? "!" : "!!",
894 str,
895 type->type == MONO_TYPE_VAR ? "class" : "method",
896 ctx->ip_offset),
897 MONO_EXCEPTION_BAD_IMAGE);
898 g_free (str);
899 return FALSE;
902 klass = mono_class_from_mono_type_internal (type);
903 mono_class_init_internal (klass);
904 if (mono_class_has_failure (klass)) {
905 if (mono_class_is_ginst (klass) && !mono_class_is_valid_generic_instantiation (NULL, klass))
906 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);
907 else
908 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);
909 return FALSE;
912 if (mono_class_is_ginst (klass) && mono_class_has_failure (mono_class_get_generic_class (klass)->container_class)) {
913 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);
914 return FALSE;
917 if (!mono_class_is_ginst (klass))
918 return TRUE;
920 if (!mono_class_is_valid_generic_instantiation (ctx, klass)) {
921 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);
922 return FALSE;
925 if (!mono_class_repect_method_constraints (ctx, klass)) {
926 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);
927 return FALSE;
930 return TRUE;
933 static verify_result_t
934 mono_method_is_valid_in_context (VerifyContext *ctx, MonoMethod *method)
936 if (!mono_type_is_valid_in_context (ctx, m_class_get_byval_arg (method->klass)))
937 return RESULT_INVALID;
939 if (!method->is_inflated)
940 return RESULT_VALID;
942 if (!mono_method_is_valid_generic_instantiation (ctx, method)) {
943 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);
944 return RESULT_INVALID;
947 if (!mono_method_repect_method_constraints (ctx, method)) {
948 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));
949 return RESULT_UNVERIFIABLE;
951 return RESULT_VALID;
955 static MonoClassField*
956 verifier_load_field (VerifyContext *ctx, int token, MonoClass **out_klass, const char *opcode) {
957 ERROR_DECL (error);
958 MonoClassField *field;
959 MonoClass *klass = NULL;
961 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
962 field = (MonoClassField *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
963 klass = field ? field->parent : NULL;
964 } else {
965 if (!IS_FIELD_DEF_OR_REF (token) || !token_bounds_check (ctx->image, token)) {
966 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);
967 return NULL;
970 field = mono_field_from_token_checked (ctx->image, token, &klass, ctx->generic_context, error);
971 mono_error_cleanup (error); /*FIXME don't swallow the error */
974 if (!field || !field->parent || !klass) {
975 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);
976 return NULL;
979 if (!mono_type_is_valid_in_context (ctx, m_class_get_byval_arg (klass)))
980 return NULL;
982 if (mono_field_get_flags (field) & FIELD_ATTRIBUTE_LITERAL) {
983 char *type_name = mono_type_get_full_name (field->parent);
984 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot reference literal field %s::%s at 0x%04x", type_name, field->name, ctx->ip_offset));
985 g_free (type_name);
986 return NULL;
989 *out_klass = klass;
990 return field;
993 static MonoMethod*
994 verifier_load_method (VerifyContext *ctx, int token, const char *opcode) {
995 MonoMethod* method;
998 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
999 method = (MonoMethod *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
1000 } else {
1001 ERROR_DECL (error);
1002 if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
1003 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);
1004 return NULL;
1007 method = mono_get_method_checked (ctx->image, token, NULL, ctx->generic_context, error);
1008 mono_error_cleanup (error); /* FIXME don't swallow this error */
1011 if (!method) {
1012 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);
1013 return NULL;
1016 if (mono_method_is_valid_in_context (ctx, method) == RESULT_INVALID)
1017 return NULL;
1019 return method;
1022 static MonoType*
1023 verifier_load_type (VerifyContext *ctx, int token, const char *opcode) {
1024 MonoType* type;
1026 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
1027 MonoClass *klass = (MonoClass *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
1028 type = klass ? m_class_get_byval_arg (klass) : NULL;
1029 } else {
1030 ERROR_DECL (error);
1031 if (!IS_TYPE_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
1032 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid type token 0x%08x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
1033 return NULL;
1035 type = mono_type_get_checked (ctx->image, token, ctx->generic_context, error);
1036 mono_error_cleanup (error); /*FIXME don't swallow the error */
1039 if (!type) {
1040 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);
1041 return NULL;
1044 if (!mono_type_is_valid_in_context (ctx, type))
1045 return NULL;
1047 return type;
1051 /* stack_slot_get_type:
1053 * Returns the stack type of @value. This value includes POINTER_MASK.
1055 * Use this function to checks that account for a managed pointer.
1057 static gint32
1058 stack_slot_get_type (ILStackDesc *value)
1060 return value->stype & RAW_TYPE_MASK;
1063 /* stack_slot_get_underlying_type:
1065 * Returns the stack type of @value. This value does not include POINTER_MASK.
1067 * Use this function is cases where the fact that the value could be a managed pointer is
1068 * irrelevant. For example, field load doesn't care about this fact of type on stack.
1070 static gint32
1071 stack_slot_get_underlying_type (ILStackDesc *value)
1073 return value->stype & TYPE_MASK;
1076 /* stack_slot_is_managed_pointer:
1078 * Returns TRUE is @value is a managed pointer.
1080 static gboolean
1081 stack_slot_is_managed_pointer (ILStackDesc *value)
1083 return (value->stype & POINTER_MASK) == POINTER_MASK;
1086 /* stack_slot_is_managed_mutability_pointer:
1088 * Returns TRUE is @value is a managed mutability pointer.
1090 static G_GNUC_UNUSED gboolean
1091 stack_slot_is_managed_mutability_pointer (ILStackDesc *value)
1093 return (value->stype & CMMP_MASK) == CMMP_MASK;
1096 /* stack_slot_is_null_literal:
1098 * Returns TRUE is @value is the null literal.
1100 static gboolean
1101 stack_slot_is_null_literal (ILStackDesc *value)
1103 return (value->stype & NULL_LITERAL_MASK) == NULL_LITERAL_MASK;
1107 /* stack_slot_is_this_pointer:
1109 * Returns TRUE is @value is the this literal
1111 static gboolean
1112 stack_slot_is_this_pointer (ILStackDesc *value)
1114 return (value->stype & THIS_POINTER_MASK) == THIS_POINTER_MASK;
1117 /* stack_slot_is_boxed_value:
1119 * Returns TRUE is @value is a boxed value
1121 static gboolean
1122 stack_slot_is_boxed_value (ILStackDesc *value)
1124 return (value->stype & BOXED_MASK) == BOXED_MASK;
1127 /* stack_slot_is_safe_byref:
1129 * Returns TRUE is @value is a safe byref
1131 static gboolean
1132 stack_slot_is_safe_byref (ILStackDesc *value)
1134 return (value->stype & SAFE_BYREF_MASK) == SAFE_BYREF_MASK;
1137 static const char *
1138 stack_slot_get_name (ILStackDesc *value)
1140 return type_names [value->stype & TYPE_MASK];
1143 enum {
1144 SAFE_BYREF_LOCAL = 1,
1145 UNSAFE_BYREF_LOCAL = 2
1147 static gboolean
1148 local_is_safe_byref (VerifyContext *ctx, unsigned int arg)
1150 return ctx->locals_verification_state [arg] == SAFE_BYREF_LOCAL;
1153 static gboolean
1154 local_is_unsafe_byref (VerifyContext *ctx, unsigned int arg)
1156 return ctx->locals_verification_state [arg] == UNSAFE_BYREF_LOCAL;
1159 #define APPEND_WITH_PREDICATE(PRED,NAME) do {\
1160 if (PRED (value)) { \
1161 if (!first) \
1162 g_string_append (str, ", "); \
1163 g_string_append (str, NAME); \
1164 first = FALSE; \
1165 } } while (0)
1167 static char*
1168 stack_slot_stack_type_full_name (ILStackDesc *value)
1170 GString *str = g_string_new ("");
1171 char *result;
1172 gboolean has_pred = FALSE, first = TRUE;
1174 if ((value->stype & TYPE_MASK) != value->stype) {
1175 g_string_append(str, "[");
1176 APPEND_WITH_PREDICATE (stack_slot_is_this_pointer, "this");
1177 APPEND_WITH_PREDICATE (stack_slot_is_boxed_value, "boxed");
1178 APPEND_WITH_PREDICATE (stack_slot_is_null_literal, "null");
1179 APPEND_WITH_PREDICATE (stack_slot_is_managed_mutability_pointer, "cmmp");
1180 APPEND_WITH_PREDICATE (stack_slot_is_managed_pointer, "mp");
1181 APPEND_WITH_PREDICATE (stack_slot_is_safe_byref, "safe-byref");
1182 has_pred = TRUE;
1185 if (mono_type_is_generic_argument (value->type) && !stack_slot_is_boxed_value (value)) {
1186 if (!has_pred)
1187 g_string_append(str, "[");
1188 if (!first)
1189 g_string_append (str, ", ");
1190 g_string_append (str, "unboxed");
1191 has_pred = TRUE;
1194 if (has_pred)
1195 g_string_append(str, "] ");
1197 g_string_append (str, stack_slot_get_name (value));
1198 result = str->str;
1199 g_string_free (str, FALSE);
1200 return result;
1203 static char*
1204 stack_slot_full_name (ILStackDesc *value)
1206 char *type_name = mono_type_full_name (value->type);
1207 char *stack_name = stack_slot_stack_type_full_name (value);
1208 char *res = g_strdup_printf ("%s (%s)", type_name, stack_name);
1209 g_free (type_name);
1210 g_free (stack_name);
1211 return res;
1214 //////////////////////////////////////////////////////////////////
1217 * mono_free_verify_list:
1219 void
1220 mono_free_verify_list (GSList *list)
1222 MonoVerifyInfoExtended *info;
1223 GSList *tmp;
1225 for (tmp = list; tmp; tmp = tmp->next) {
1226 info = (MonoVerifyInfoExtended *)tmp->data;
1227 g_free (info->info.message);
1228 g_free (info);
1230 g_slist_free (list);
1233 #define ADD_ERROR(list,msg) \
1234 do { \
1235 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1236 vinfo->info.status = MONO_VERIFY_ERROR; \
1237 vinfo->info.message = (msg); \
1238 (list) = g_slist_prepend ((list), vinfo); \
1239 } while (0)
1241 #define ADD_WARN(list,code,msg) \
1242 do { \
1243 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1244 vinfo->info.status = (code); \
1245 vinfo->info.message = (msg); \
1246 (list) = g_slist_prepend ((list), vinfo); \
1247 } while (0)
1249 #define ADD_INVALID(list,msg) \
1250 do { \
1251 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1252 vinfo->status = MONO_VERIFY_ERROR; \
1253 vinfo->message = (msg); \
1254 (list) = g_slist_prepend ((list), vinfo); \
1255 /*G_BREAKPOINT ();*/ \
1256 goto invalid_cil; \
1257 } while (0)
1259 #define CHECK_STACK_UNDERFLOW(num) \
1260 do { \
1261 if (cur_stack < (num)) \
1262 ADD_INVALID (list, g_strdup_printf ("Stack underflow at 0x%04x (%d items instead of %d)", ip_offset, cur_stack, (num))); \
1263 } while (0)
1265 #define CHECK_STACK_OVERFLOW() \
1266 do { \
1267 if (cur_stack >= max_stack) \
1268 ADD_INVALID (list, g_strdup_printf ("Maxstack exceeded at 0x%04x", ip_offset)); \
1269 } while (0)
1272 static int
1273 in_any_block (MonoMethodHeader *header, guint offset)
1275 int i;
1276 MonoExceptionClause *clause;
1278 for (i = 0; i < header->num_clauses; ++i) {
1279 clause = &header->clauses [i];
1280 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1281 return 1;
1282 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1283 return 1;
1284 if (MONO_OFFSET_IN_FILTER (clause, offset))
1285 return 1;
1287 return 0;
1291 * in_any_exception_block:
1293 * Returns TRUE is @offset is part of any exception clause (filter, handler, catch, finally or fault).
1295 static gboolean
1296 in_any_exception_block (MonoMethodHeader *header, guint offset)
1298 int i;
1299 MonoExceptionClause *clause;
1301 for (i = 0; i < header->num_clauses; ++i) {
1302 clause = &header->clauses [i];
1303 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1304 return TRUE;
1305 if (MONO_OFFSET_IN_FILTER (clause, offset))
1306 return TRUE;
1308 return FALSE;
1312 * is_valid_branch_instruction:
1314 * Verify if it's valid to perform a branch from @offset to @target.
1315 * This should be used with br and brtrue/false.
1316 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1317 * The major difference from other similiar functions is that branching into a
1318 * finally/fault block is invalid instead of just unverifiable.
1320 static int
1321 is_valid_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1323 int i;
1324 MonoExceptionClause *clause;
1326 for (i = 0; i < header->num_clauses; ++i) {
1327 clause = &header->clauses [i];
1328 /*branching into a finally block is invalid*/
1329 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) &&
1330 !MONO_OFFSET_IN_HANDLER (clause, offset) &&
1331 MONO_OFFSET_IN_HANDLER (clause, target))
1332 return 2;
1334 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1335 return 1;
1336 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1337 return 1;
1338 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1339 return 1;
1341 return 0;
1345 * is_valid_cmp_branch_instruction:
1347 * Verify if it's valid to perform a branch from @offset to @target.
1348 * This should be used with binary comparison branching instruction, like beq, bge and similars.
1349 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1351 * The major differences from other similar functions are that most errors lead to invalid
1352 * code and only branching out of finally, filter or fault clauses is unverifiable.
1354 static int
1355 is_valid_cmp_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1357 int i;
1358 MonoExceptionClause *clause;
1360 for (i = 0; i < header->num_clauses; ++i) {
1361 clause = &header->clauses [i];
1362 /*branching out of a handler or finally*/
1363 if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE &&
1364 MONO_OFFSET_IN_HANDLER (clause, offset) &&
1365 !MONO_OFFSET_IN_HANDLER (clause, target))
1366 return 1;
1368 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1369 return 2;
1370 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1371 return 2;
1372 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1373 return 2;
1375 return 0;
1379 * A leave can't escape a finally block
1381 static int
1382 is_correct_leave (MonoMethodHeader *header, guint offset, guint target)
1384 int i;
1385 MonoExceptionClause *clause;
1387 for (i = 0; i < header->num_clauses; ++i) {
1388 clause = &header->clauses [i];
1389 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY && MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
1390 return 0;
1391 if (MONO_OFFSET_IN_FILTER (clause, offset))
1392 return 0;
1394 return 1;
1398 * A rethrow can't happen outside of a catch handler.
1400 static int
1401 is_correct_rethrow (MonoMethodHeader *header, guint offset)
1403 int i;
1404 MonoExceptionClause *clause;
1406 for (i = 0; i < header->num_clauses; ++i) {
1407 clause = &header->clauses [i];
1408 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1409 return 1;
1411 return 0;
1415 * An endfinally can't happen outside of a finally/fault handler.
1417 static int
1418 is_correct_endfinally (MonoMethodHeader *header, guint offset)
1420 int i;
1421 MonoExceptionClause *clause;
1423 for (i = 0; i < header->num_clauses; ++i) {
1424 clause = &header->clauses [i];
1425 if (MONO_OFFSET_IN_HANDLER (clause, offset) && (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY))
1426 return 1;
1428 return 0;
1433 * An endfilter can only happens inside a filter clause.
1434 * In non-strict mode filter is allowed inside the handler clause too
1436 static MonoExceptionClause *
1437 is_correct_endfilter (VerifyContext *ctx, guint offset)
1439 int i;
1440 MonoExceptionClause *clause;
1442 for (i = 0; i < ctx->header->num_clauses; ++i) {
1443 clause = &ctx->header->clauses [i];
1444 if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER)
1445 continue;
1446 if (MONO_OFFSET_IN_FILTER (clause, offset))
1447 return clause;
1448 if (!IS_STRICT_MODE (ctx) && MONO_OFFSET_IN_HANDLER (clause, offset))
1449 return clause;
1451 return NULL;
1456 * Non-strict endfilter can happens inside a try block or any handler block
1458 static int
1459 is_unverifiable_endfilter (VerifyContext *ctx, guint offset)
1461 int i;
1462 MonoExceptionClause *clause;
1464 for (i = 0; i < ctx->header->num_clauses; ++i) {
1465 clause = &ctx->header->clauses [i];
1466 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1467 return 1;
1469 return 0;
1472 static gboolean
1473 is_valid_bool_arg (ILStackDesc *arg)
1475 if (stack_slot_is_managed_pointer (arg) || stack_slot_is_boxed_value (arg) || stack_slot_is_null_literal (arg))
1476 return TRUE;
1479 switch (stack_slot_get_underlying_type (arg)) {
1480 case TYPE_I4:
1481 case TYPE_I8:
1482 case TYPE_NATIVE_INT:
1483 case TYPE_PTR:
1484 return TRUE;
1485 case TYPE_COMPLEX:
1486 g_assert (arg->type);
1487 switch (arg->type->type) {
1488 case MONO_TYPE_CLASS:
1489 case MONO_TYPE_STRING:
1490 case MONO_TYPE_OBJECT:
1491 case MONO_TYPE_SZARRAY:
1492 case MONO_TYPE_ARRAY:
1493 case MONO_TYPE_FNPTR:
1494 case MONO_TYPE_PTR:
1495 return TRUE;
1496 case MONO_TYPE_GENERICINST:
1497 /*We need to check if the container class
1498 * of the generic type is a valuetype, iow:
1499 * is it a "class Foo<T>" or a "struct Foo<T>"?
1501 return !m_class_is_valuetype (arg->type->data.generic_class->container_class);
1502 default:
1503 return FALSE;
1505 default:
1506 return FALSE;
1511 /*Type manipulation helper*/
1513 /*Returns the byref version of the supplied MonoType*/
1514 static MonoType*
1515 mono_type_get_type_byref (MonoType *type)
1517 if (type->byref)
1518 return type;
1519 return m_class_get_this_arg (mono_class_from_mono_type_internal (type));
1523 /*Returns the byval version of the supplied MonoType*/
1524 static MonoType*
1525 mono_type_get_type_byval (MonoType *type)
1527 if (!type->byref)
1528 return type;
1529 return m_class_get_byval_arg (mono_class_from_mono_type_internal (type));
1532 static MonoType*
1533 mono_type_from_stack_slot (ILStackDesc *slot)
1535 if (stack_slot_is_managed_pointer (slot))
1536 return mono_type_get_type_byref (slot->type);
1537 return slot->type;
1540 /*Stack manipulation code*/
1542 static void
1543 ensure_stack_size (ILCodeDesc *stack, int required)
1545 int new_size = 8;
1546 ILStackDesc *tmp;
1548 if (required < stack->max_size)
1549 return;
1551 /* We don't have to worry about the exponential growth since stack_copy prune unused space */
1552 new_size = MAX (8, MAX (required, stack->max_size * 2));
1554 g_assert (new_size >= stack->size);
1555 g_assert (new_size >= required);
1557 tmp = g_new0 (ILStackDesc, new_size);
1558 _MEM_ALLOC (sizeof (ILStackDesc) * new_size);
1560 if (stack->stack) {
1561 if (stack->size)
1562 memcpy (tmp, stack->stack, stack->size * sizeof (ILStackDesc));
1563 g_free (stack->stack);
1564 _MEM_FREE (sizeof (ILStackDesc) * stack->max_size);
1567 stack->stack = tmp;
1568 stack->max_size = new_size;
1571 static void
1572 stack_init (VerifyContext *ctx, ILCodeDesc *state)
1574 if (state->flags & IL_CODE_FLAG_STACK_INITED)
1575 return;
1576 state->size = state->max_size = 0;
1577 state->flags |= IL_CODE_FLAG_STACK_INITED;
1580 static void
1581 stack_copy (ILCodeDesc *to, ILCodeDesc *from)
1583 ensure_stack_size (to, from->size);
1584 to->size = from->size;
1586 /*stack copy happens at merge points, which have small stacks*/
1587 if (from->size)
1588 memcpy (to->stack, from->stack, sizeof (ILStackDesc) * from->size);
1591 static void
1592 copy_stack_value (ILStackDesc *to, ILStackDesc *from)
1594 to->stype = from->stype;
1595 to->type = from->type;
1596 to->method = from->method;
1599 static int
1600 check_underflow (VerifyContext *ctx, int size)
1602 if (ctx->eval.size < size) {
1603 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack underflow, required %d, but have %d at 0x%04x", size, ctx->eval.size, ctx->ip_offset));
1604 return 0;
1606 return 1;
1609 static int
1610 check_overflow (VerifyContext *ctx)
1612 if (ctx->eval.size >= ctx->max_stack) {
1613 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have stack-depth %d at 0x%04x", ctx->eval.size + 1, ctx->ip_offset));
1614 return 0;
1616 return 1;
1619 /*This reject out PTR, FNPTR and TYPEDBYREF*/
1620 static gboolean
1621 check_unmanaged_pointer (VerifyContext *ctx, ILStackDesc *value)
1623 if (stack_slot_get_type (value) == TYPE_PTR) {
1624 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1625 return 0;
1627 return 1;
1630 /*TODO verify if MONO_TYPE_TYPEDBYREF is not allowed here as well.*/
1631 static gboolean
1632 check_unverifiable_type (VerifyContext *ctx, MonoType *type)
1634 if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
1635 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1636 return 0;
1638 return 1;
1641 static ILStackDesc *
1642 stack_push (VerifyContext *ctx)
1644 g_assert (ctx->eval.size < ctx->max_stack);
1645 g_assert (ctx->eval.size <= ctx->eval.max_size);
1647 ensure_stack_size (&ctx->eval, ctx->eval.size + 1);
1649 return & ctx->eval.stack [ctx->eval.size++];
1652 static ILStackDesc *
1653 stack_push_val (VerifyContext *ctx, int stype, MonoType *type)
1655 ILStackDesc *top = stack_push (ctx);
1656 top->stype = stype;
1657 top->type = type;
1658 return top;
1661 static ILStackDesc *
1662 stack_pop (VerifyContext *ctx)
1664 ILStackDesc *ret;
1665 g_assert (ctx->eval.size > 0);
1666 ret = ctx->eval.stack + --ctx->eval.size;
1667 if ((ret->stype & UNINIT_THIS_MASK) == UNINIT_THIS_MASK)
1668 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Found use of uninitialized 'this ptr' ref at 0x%04x", ctx->ip_offset));
1669 return ret;
1672 /* This function allows to safely pop an unititialized this ptr from
1673 * the eval stack without marking the method as unverifiable.
1675 static ILStackDesc *
1676 stack_pop_safe (VerifyContext *ctx)
1678 g_assert (ctx->eval.size > 0);
1679 return ctx->eval.stack + --ctx->eval.size;
1682 /*Positive number distance from stack top. [0] is stack top, [1] is the one below*/
1683 static ILStackDesc*
1684 stack_peek (VerifyContext *ctx, int distance)
1686 g_assert (ctx->eval.size - distance > 0);
1687 return ctx->eval.stack + (ctx->eval.size - 1 - distance);
1690 static ILStackDesc *
1691 stack_push_stack_val (VerifyContext *ctx, ILStackDesc *value)
1693 ILStackDesc *top = stack_push (ctx);
1694 copy_stack_value (top, value);
1695 return top;
1698 /* Returns the MonoType associated with the token, or NULL if it is invalid.
1700 * A boxable type can be either a reference or value type, but cannot be a byref type or an unmanaged pointer
1701 * */
1702 static MonoType*
1703 get_boxable_mono_type (VerifyContext* ctx, int token, const char *opcode)
1705 MonoType *type;
1706 MonoClass *klass;
1708 if (!(type = verifier_load_type (ctx, token, opcode)))
1709 return NULL;
1711 if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
1712 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type for %s at 0x%04x", opcode, ctx->ip_offset));
1713 return NULL;
1716 if (type->type == MONO_TYPE_VOID) {
1717 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type for %s at 0x%04x", opcode, ctx->ip_offset));
1718 return NULL;
1721 if (type->type == MONO_TYPE_TYPEDBYREF)
1722 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid use of typedbyref for %s at 0x%04x", opcode, ctx->ip_offset));
1724 if (!(klass = mono_class_from_mono_type_internal (type)))
1725 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not retrieve type token for %s at 0x%04x", opcode, ctx->ip_offset));
1727 if (mono_class_is_gtd (klass) && type->type != MONO_TYPE_GENERICINST)
1728 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));
1730 check_unverifiable_type (ctx, type);
1731 return type;
1735 /*operation result tables */
1737 static const unsigned char bin_op_table [TYPE_MAX][TYPE_MAX] = {
1738 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1739 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1740 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1741 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1742 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1743 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1746 static const unsigned char add_table [TYPE_MAX][TYPE_MAX] = {
1747 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1748 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1749 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1750 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1751 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1752 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1755 static const unsigned char sub_table [TYPE_MAX][TYPE_MAX] = {
1756 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1757 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1758 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1759 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1760 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1761 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1764 static const unsigned char int_bin_op_table [TYPE_MAX][TYPE_MAX] = {
1765 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1766 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1767 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1768 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1769 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1770 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1773 static const unsigned char shift_op_table [TYPE_MAX][TYPE_MAX] = {
1774 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1775 {TYPE_I8, TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV},
1776 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1777 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1778 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1779 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1782 static const unsigned char cmp_br_op [TYPE_MAX][TYPE_MAX] = {
1783 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1784 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1785 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1786 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1787 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV},
1788 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1791 static const unsigned char cmp_br_eq_op [TYPE_MAX][TYPE_MAX] = {
1792 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1793 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1794 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV},
1795 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1796 {TYPE_INV, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_I4, TYPE_INV},
1797 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4},
1800 static const unsigned char add_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
1801 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1802 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1803 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1804 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1805 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1806 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1809 static const unsigned char sub_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
1810 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1811 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1812 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1813 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1814 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1815 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1818 static const unsigned char bin_ovf_table [TYPE_MAX][TYPE_MAX] = {
1819 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1820 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1821 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1822 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1823 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1824 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1827 #ifdef MONO_VERIFIER_DEBUG
1829 /*debug helpers */
1830 static void
1831 dump_stack_value (ILStackDesc *value)
1833 printf ("[(%x)(%x)", value->type->type, value->stype);
1835 if (stack_slot_is_this_pointer (value))
1836 printf ("[this] ");
1838 if (stack_slot_is_boxed_value (value))
1839 printf ("[boxed] ");
1841 if (stack_slot_is_null_literal (value))
1842 printf ("[null] ");
1844 if (stack_slot_is_managed_mutability_pointer (value))
1845 printf ("Controled Mutability MP: ");
1847 if (stack_slot_is_managed_pointer (value))
1848 printf ("Managed Pointer to: ");
1850 if (stack_slot_is_safe_byref (value))
1851 printf ("Safe ByRef to: ");
1853 switch (stack_slot_get_underlying_type (value)) {
1854 case TYPE_INV:
1855 printf ("invalid type]");
1856 return;
1857 case TYPE_I4:
1858 printf ("int32]");
1859 return;
1860 case TYPE_I8:
1861 printf ("int64]");
1862 return;
1863 case TYPE_NATIVE_INT:
1864 printf ("native int]");
1865 return;
1866 case TYPE_R8:
1867 printf ("float64]");
1868 return;
1869 case TYPE_PTR:
1870 printf ("unmanaged pointer]");
1871 return;
1872 case TYPE_COMPLEX:
1873 switch (value->type->type) {
1874 case MONO_TYPE_CLASS:
1875 case MONO_TYPE_VALUETYPE:
1876 printf ("complex] (%s)", value->type->data.klass->name);
1877 return;
1878 case MONO_TYPE_STRING:
1879 printf ("complex] (string)");
1880 return;
1881 case MONO_TYPE_OBJECT:
1882 printf ("complex] (object)");
1883 return;
1884 case MONO_TYPE_SZARRAY:
1885 printf ("complex] (%s [])", value->type->data.klass->name);
1886 return;
1887 case MONO_TYPE_ARRAY:
1888 printf ("complex] (%s [%d %d %d])",
1889 value->type->data.array->eklass->name,
1890 value->type->data.array->rank,
1891 value->type->data.array->numsizes,
1892 value->type->data.array->numlobounds);
1893 return;
1894 case MONO_TYPE_GENERICINST:
1895 printf ("complex] (inst of %s )", value->type->data.generic_class->container_class->name);
1896 return;
1897 case MONO_TYPE_VAR:
1898 printf ("complex] (type generic param !%d - %s) ", value->type->data.generic_param->num, mono_generic_param_name (value->type->data.generic_param));
1899 return;
1900 case MONO_TYPE_MVAR:
1901 printf ("complex] (method generic param !!%d - %s) ", value->type->data.generic_param->num, mono_generic_param_name (value->type->data.generic_param));
1902 return;
1903 default: {
1904 //should be a boxed value
1905 char * name = mono_type_full_name (value->type);
1906 printf ("complex] %s", name);
1907 g_free (name);
1908 return;
1911 default:
1912 printf ("unknown stack %x type]\n", value->stype);
1913 g_assert_not_reached ();
1917 static void
1918 dump_stack_state (ILCodeDesc *state)
1920 int i;
1922 printf ("(%d) ", state->size);
1923 for (i = 0; i < state->size; ++i)
1924 dump_stack_value (state->stack + i);
1925 printf ("\n");
1927 #endif
1930 * is_array_type_compatible:
1932 * Returns TRUE if candidate array type can be assigned to target.
1934 * Both parameters MUST be of type MONO_TYPE_ARRAY (target->type == MONO_TYPE_ARRAY)
1936 static gboolean
1937 is_array_type_compatible (MonoType *target, MonoType *candidate)
1939 MonoArrayType *left = target->data.array;
1940 MonoArrayType *right = candidate->data.array;
1942 g_assert (target->type == MONO_TYPE_ARRAY);
1943 g_assert (candidate->type == MONO_TYPE_ARRAY);
1945 if (left->rank != right->rank)
1946 return FALSE;
1948 return verifier_class_is_assignable_from (left->eklass, right->eklass);
1951 static int
1952 get_stack_type (MonoType *type)
1954 int mask = 0;
1955 int type_kind = type->type;
1956 if (type->byref)
1957 mask = POINTER_MASK;
1958 /*TODO handle CMMP_MASK */
1960 handle_enum:
1961 switch (type_kind) {
1962 case MONO_TYPE_I1:
1963 case MONO_TYPE_U1:
1964 case MONO_TYPE_BOOLEAN:
1965 case MONO_TYPE_I2:
1966 case MONO_TYPE_U2:
1967 case MONO_TYPE_CHAR:
1968 case MONO_TYPE_I4:
1969 case MONO_TYPE_U4:
1970 return TYPE_I4 | mask;
1972 case MONO_TYPE_I:
1973 case MONO_TYPE_U:
1974 return TYPE_NATIVE_INT | mask;
1976 /* FIXME: the spec says that you cannot have a pointer to method pointer, do we need to check this here? */
1977 case MONO_TYPE_FNPTR:
1978 case MONO_TYPE_PTR:
1979 case MONO_TYPE_TYPEDBYREF:
1980 return TYPE_PTR | mask;
1982 case MONO_TYPE_VAR:
1983 case MONO_TYPE_MVAR:
1985 case MONO_TYPE_CLASS:
1986 case MONO_TYPE_STRING:
1987 case MONO_TYPE_OBJECT:
1988 case MONO_TYPE_SZARRAY:
1989 case MONO_TYPE_ARRAY:
1990 return TYPE_COMPLEX | mask;
1992 case MONO_TYPE_I8:
1993 case MONO_TYPE_U8:
1994 return TYPE_I8 | mask;
1996 case MONO_TYPE_R4:
1997 case MONO_TYPE_R8:
1998 return TYPE_R8 | mask;
2000 case MONO_TYPE_GENERICINST:
2001 case MONO_TYPE_VALUETYPE:
2002 if (mono_type_is_enum_type (type)) {
2003 type = mono_type_get_underlying_type_any (type);
2004 if (!type)
2005 return FALSE;
2006 type_kind = type->type;
2007 goto handle_enum;
2008 } else {
2009 return TYPE_COMPLEX | mask;
2012 default:
2013 return TYPE_INV;
2017 /* convert MonoType to ILStackDesc format (stype) */
2018 static gboolean
2019 set_stack_value (VerifyContext *ctx, ILStackDesc *stack, MonoType *type, int take_addr)
2021 int mask = 0;
2022 int type_kind = type->type;
2024 if (type->byref || take_addr)
2025 mask = POINTER_MASK;
2026 /* TODO handle CMMP_MASK */
2028 handle_enum:
2029 stack->type = type;
2031 switch (type_kind) {
2032 case MONO_TYPE_I1:
2033 case MONO_TYPE_U1:
2034 case MONO_TYPE_BOOLEAN:
2035 case MONO_TYPE_I2:
2036 case MONO_TYPE_U2:
2037 case MONO_TYPE_CHAR:
2038 case MONO_TYPE_I4:
2039 case MONO_TYPE_U4:
2040 stack->stype = TYPE_I4 | mask;
2041 break;
2042 case MONO_TYPE_I:
2043 case MONO_TYPE_U:
2044 stack->stype = TYPE_NATIVE_INT | mask;
2045 break;
2047 /*FIXME: Do we need to check if it's a pointer to the method pointer? The spec says it' illegal to have that.*/
2048 case MONO_TYPE_FNPTR:
2049 case MONO_TYPE_PTR:
2050 case MONO_TYPE_TYPEDBYREF:
2051 stack->stype = TYPE_PTR | mask;
2052 break;
2054 case MONO_TYPE_CLASS:
2055 case MONO_TYPE_STRING:
2056 case MONO_TYPE_OBJECT:
2057 case MONO_TYPE_SZARRAY:
2058 case MONO_TYPE_ARRAY:
2060 case MONO_TYPE_VAR:
2061 case MONO_TYPE_MVAR:
2062 stack->stype = TYPE_COMPLEX | mask;
2063 break;
2065 case MONO_TYPE_I8:
2066 case MONO_TYPE_U8:
2067 stack->stype = TYPE_I8 | mask;
2068 break;
2069 case MONO_TYPE_R4:
2070 case MONO_TYPE_R8:
2071 stack->stype = TYPE_R8 | mask;
2072 break;
2073 case MONO_TYPE_GENERICINST:
2074 case MONO_TYPE_VALUETYPE:
2075 if (mono_type_is_enum_type (type)) {
2076 MonoType *utype = mono_type_get_underlying_type_any (type);
2077 if (!utype) {
2078 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not resolve underlying type of %x at %d", type->type, ctx->ip_offset));
2079 return FALSE;
2081 type = utype;
2082 type_kind = type->type;
2083 goto handle_enum;
2084 } else {
2085 stack->stype = TYPE_COMPLEX | mask;
2086 break;
2088 default:
2089 VERIFIER_DEBUG ( printf ("unknown type 0x%02x in eval stack type\n", type->type); );
2090 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Illegal value set on stack 0x%02x at %d", type->type, ctx->ip_offset));
2091 return FALSE;
2093 return TRUE;
2097 * init_stack_with_value_at_exception_boundary:
2099 * Initialize the stack and push a given type.
2100 * The instruction is marked as been on the exception boundary.
2102 static void
2103 init_stack_with_value_at_exception_boundary (VerifyContext *ctx, ILCodeDesc *code, MonoClass *klass)
2105 ERROR_DECL (error);
2106 MonoType *type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (klass), ctx->generic_context, error);
2108 if (!is_ok (error)) {
2109 char *name = mono_type_get_full_name (klass);
2110 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid class %s used for exception", name));
2111 g_free (name);
2112 mono_error_cleanup (error);
2113 return;
2116 if (!ctx->max_stack) {
2117 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack overflow at 0x%04x", ctx->ip_offset));
2118 return;
2121 stack_init (ctx, code);
2122 ensure_stack_size (code, 1);
2123 set_stack_value (ctx, code->stack, type, FALSE);
2124 ctx->exception_types = g_slist_prepend (ctx->exception_types, type);
2125 code->size = 1;
2126 code->flags |= IL_CODE_FLAG_WAS_TARGET;
2127 if (mono_type_is_generic_argument (type))
2128 code->stack->stype |= BOXED_MASK;
2130 /* Class lazy loading functions */
2131 static GENERATE_GET_CLASS_WITH_CACHE (ienumerable, "System.Collections.Generic", "IEnumerable`1")
2132 static GENERATE_GET_CLASS_WITH_CACHE (icollection, "System.Collections.Generic", "ICollection`1")
2133 static GENERATE_GET_CLASS_WITH_CACHE (ireadonly_list, "System.Collections.Generic", "IReadOnlyList`1")
2134 static GENERATE_GET_CLASS_WITH_CACHE (ireadonly_collection, "System.Collections.Generic", "IReadOnlyCollection`1")
2137 static MonoClass*
2138 get_ienumerable_class (void)
2140 return mono_class_get_ienumerable_class ();
2143 static MonoClass*
2144 get_icollection_class (void)
2146 return mono_class_get_icollection_class ();
2149 static MonoClass*
2150 get_ireadonlylist_class (void)
2152 return mono_class_get_ireadonly_list_class ();
2155 static MonoClass*
2156 get_ireadonlycollection_class (void)
2158 return mono_class_get_ireadonly_collection_class ();
2161 static MonoClass*
2162 inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
2164 MonoType *args [1];
2165 args [0] = m_class_get_byval_arg (arg0);
2167 return mono_class_bind_generic_parameters (gtype, 1, args, FALSE);
2170 static gboolean
2171 verifier_inflate_and_check_compat (MonoClass *target, MonoClass *gtd, MonoClass *arg)
2173 MonoClass *tmp;
2174 if (!(tmp = inflate_class_one_arg (gtd, arg)))
2175 return FALSE;
2176 if (mono_class_is_variant_compatible (target, tmp, TRUE))
2177 return TRUE;
2178 return FALSE;
2181 static gboolean
2182 verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate)
2184 MonoClass *iface_gtd;
2186 if (target == candidate)
2187 return TRUE;
2189 if (mono_class_has_variant_generic_params (target)) {
2190 if (MONO_CLASS_IS_INTERFACE_INTERNAL (target)) {
2191 if (MONO_CLASS_IS_INTERFACE_INTERNAL (candidate) && mono_class_is_variant_compatible (target, candidate, TRUE))
2192 return TRUE;
2194 if (m_class_get_rank (candidate) == 1) {
2195 MonoClass *candidate_element_class = m_class_get_element_class (candidate);
2196 if (verifier_inflate_and_check_compat (target, mono_defaults.generic_ilist_class, candidate_element_class))
2197 return TRUE;
2198 if (verifier_inflate_and_check_compat (target, get_icollection_class (), candidate_element_class))
2199 return TRUE;
2200 if (verifier_inflate_and_check_compat (target, get_ienumerable_class (), candidate_element_class))
2201 return TRUE;
2202 if (verifier_inflate_and_check_compat (target, get_ireadonlylist_class (), candidate_element_class))
2203 return TRUE;
2204 if (verifier_inflate_and_check_compat (target, get_ireadonlycollection_class (), candidate_element_class))
2205 return TRUE;
2206 } else {
2207 ERROR_DECL (error);
2208 int i;
2209 while (candidate && candidate != mono_defaults.object_class) {
2210 mono_class_setup_interfaces (candidate, error);
2211 if (!is_ok (error)) {
2212 mono_error_cleanup (error);
2213 return FALSE;
2216 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
2217 guint16 candidate_interface_offsets_count = m_class_get_interface_offsets_count (candidate);
2218 MonoClass **candidate_interfaces_packed = m_class_get_interfaces_packed (candidate);
2219 for (i = 0; i < candidate_interface_offsets_count; ++i) {
2220 MonoClass *iface = candidate_interfaces_packed [i];
2221 if (mono_class_is_variant_compatible (target, iface, TRUE))
2222 return TRUE;
2225 guint16 candidate_interface_count = m_class_get_interface_count (candidate);
2226 MonoClass **candidate_interfaces = m_class_get_interfaces (candidate);
2227 for (i = 0; i < candidate_interface_count; ++i) {
2228 MonoClass *iface = candidate_interfaces [i];
2229 if (mono_class_is_variant_compatible (target, iface, TRUE))
2230 return TRUE;
2232 candidate = m_class_get_parent (candidate);
2235 } else if (m_class_is_delegate (target)) {
2236 if (mono_class_is_variant_compatible (target, candidate, TRUE))
2237 return TRUE;
2239 return FALSE;
2242 if (mono_class_is_assignable_from_internal (target, candidate))
2243 return TRUE;
2245 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (target) || !mono_class_is_ginst (target) || m_class_get_rank (candidate) != 1)
2246 return FALSE;
2248 iface_gtd = mono_class_get_generic_class (target)->container_class;
2249 if (iface_gtd != mono_defaults.generic_ilist_class && iface_gtd != get_icollection_class () && iface_gtd != get_ienumerable_class ())
2250 return FALSE;
2252 target = mono_class_from_mono_type_internal (mono_class_get_generic_class (target)->context.class_inst->type_argv [0]);
2253 candidate = m_class_get_element_class (candidate);
2255 return TRUE;
2258 /*Verify if type 'candidate' can be stored in type 'target'.
2260 * If strict, check for the underlying type and not the verification stack types
2262 static gboolean
2263 verify_type_compatibility_full (VerifyContext *ctx, MonoType *target, MonoType *candidate, gboolean strict)
2265 #define IS_ONE_OF3(T, A, B, C) (T == A || T == B || T == C)
2266 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
2268 MonoType *original_candidate = candidate;
2269 VERIFIER_DEBUG ( printf ("checking type compatibility %s x %s strict %d\n", mono_type_full_name (target), mono_type_full_name (candidate), strict); );
2271 /*only one is byref */
2272 if (candidate->byref ^ target->byref) {
2273 /* converting from native int to byref*/
2274 if (get_stack_type (candidate) == TYPE_NATIVE_INT && target->byref) {
2275 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("using byref native int at 0x%04x", ctx->ip_offset));
2276 return TRUE;
2278 return FALSE;
2280 strict |= target->byref;
2281 /*From now on we don't care about byref anymore, so it's ok to discard it here*/
2282 candidate = mono_type_get_underlying_type_any (candidate);
2284 handle_enum:
2285 switch (target->type) {
2286 case MONO_TYPE_VOID:
2287 return candidate->type == MONO_TYPE_VOID;
2288 case MONO_TYPE_I1:
2289 case MONO_TYPE_U1:
2290 case MONO_TYPE_BOOLEAN:
2291 if (strict)
2292 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I1, MONO_TYPE_U1, MONO_TYPE_BOOLEAN);
2293 case MONO_TYPE_I2:
2294 case MONO_TYPE_U2:
2295 case MONO_TYPE_CHAR:
2296 if (strict)
2297 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I2, MONO_TYPE_U2, MONO_TYPE_CHAR);
2298 case MONO_TYPE_I4:
2299 case MONO_TYPE_U4: {
2300 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2301 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2302 if (strict)
2303 return is_native_int || is_int4;
2304 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2307 case MONO_TYPE_I8:
2308 case MONO_TYPE_U8:
2309 return IS_ONE_OF2 (candidate->type, MONO_TYPE_I8, MONO_TYPE_U8);
2311 case MONO_TYPE_R4:
2312 case MONO_TYPE_R8:
2313 if (strict)
2314 return candidate->type == target->type;
2315 return IS_ONE_OF2 (candidate->type, MONO_TYPE_R4, MONO_TYPE_R8);
2317 case MONO_TYPE_I:
2318 case MONO_TYPE_U: {
2319 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2320 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2321 if (strict)
2322 return is_native_int || is_int4;
2323 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2326 case MONO_TYPE_PTR:
2327 if (candidate->type != MONO_TYPE_PTR)
2328 return FALSE;
2329 /* check the underlying type */
2330 return verify_type_compatibility_full (ctx, target->data.type, candidate->data.type, TRUE);
2332 case MONO_TYPE_FNPTR: {
2333 MonoMethodSignature *left, *right;
2334 if (candidate->type != MONO_TYPE_FNPTR)
2335 return FALSE;
2337 left = mono_type_get_signature_internal (target);
2338 right = mono_type_get_signature_internal (candidate);
2339 return mono_metadata_signature_equal (left, right) && left->call_convention == right->call_convention;
2342 case MONO_TYPE_GENERICINST: {
2343 MonoClass *target_klass;
2344 MonoClass *candidate_klass;
2345 if (mono_type_is_enum_type (target)) {
2346 target = mono_type_get_underlying_type_any (target);
2347 if (!target)
2348 return FALSE;
2349 goto handle_enum;
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 target_klass = mono_class_from_mono_type_internal (target);
2359 candidate_klass = mono_class_from_mono_type_internal (candidate);
2360 if (mono_class_is_nullable (target_klass)) {
2361 if (!mono_class_is_nullable (candidate_klass))
2362 return FALSE;
2363 return target_klass == candidate_klass;
2365 return verifier_class_is_assignable_from (target_klass, candidate_klass);
2368 case MONO_TYPE_STRING:
2369 return candidate->type == MONO_TYPE_STRING;
2371 case MONO_TYPE_CLASS:
2373 * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
2374 * to take boxing status into account.
2376 if (mono_type_is_generic_argument (original_candidate))
2377 return FALSE;
2379 if (candidate->type == MONO_TYPE_VALUETYPE)
2380 return FALSE;
2382 /* If candidate is an enum it should return true for System.Enum and supertypes.
2383 * That's why here we use the original type and not the underlying type.
2385 return verifier_class_is_assignable_from (target->data.klass, mono_class_from_mono_type_internal (original_candidate));
2387 case MONO_TYPE_OBJECT:
2388 return MONO_TYPE_IS_REFERENCE (candidate);
2390 case MONO_TYPE_SZARRAY: {
2391 MonoClass *left;
2392 MonoClass *right;
2393 if (candidate->type != MONO_TYPE_SZARRAY)
2394 return FALSE;
2396 left = mono_class_from_mono_type_internal (target);
2397 right = mono_class_from_mono_type_internal (candidate);
2399 return verifier_class_is_assignable_from (left, right);
2402 case MONO_TYPE_ARRAY:
2403 if (candidate->type != MONO_TYPE_ARRAY)
2404 return FALSE;
2405 return is_array_type_compatible (target, candidate);
2407 case MONO_TYPE_TYPEDBYREF:
2408 return candidate->type == MONO_TYPE_TYPEDBYREF;
2410 case MONO_TYPE_VALUETYPE: {
2411 MonoClass *target_klass;
2412 MonoClass *candidate_klass;
2414 if (candidate->type == MONO_TYPE_CLASS)
2415 return FALSE;
2417 target_klass = mono_class_from_mono_type_internal (target);
2418 candidate_klass = mono_class_from_mono_type_internal (candidate);
2419 if (target_klass == candidate_klass)
2420 return TRUE;
2421 if (mono_type_is_enum_type (target)) {
2422 target = mono_type_get_underlying_type_any (target);
2423 if (!target)
2424 return FALSE;
2425 goto handle_enum;
2427 return FALSE;
2430 case MONO_TYPE_VAR:
2431 if (candidate->type != MONO_TYPE_VAR)
2432 return FALSE;
2433 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2435 case MONO_TYPE_MVAR:
2436 if (candidate->type != MONO_TYPE_MVAR)
2437 return FALSE;
2438 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2440 default:
2441 VERIFIER_DEBUG ( printf ("unknown store type %d\n", target->type); );
2442 g_assert_not_reached ();
2443 return FALSE;
2445 return 1;
2446 #undef IS_ONE_OF3
2447 #undef IS_ONE_OF2
2450 static gboolean
2451 verify_type_compatibility (VerifyContext *ctx, MonoType *target, MonoType *candidate)
2453 return verify_type_compatibility_full (ctx, target, candidate, FALSE);
2457 * Returns the generic param bound to the context been verified.
2460 static MonoGenericParam*
2461 get_generic_param (VerifyContext *ctx, MonoType *param)
2463 guint16 param_num = mono_type_get_generic_param_num (param);
2464 if (param->type == MONO_TYPE_VAR) {
2465 if (!ctx->generic_context->class_inst || ctx->generic_context->class_inst->type_argc <= param_num) {
2466 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic type argument %d", param_num));
2467 return NULL;
2469 return ctx->generic_context->class_inst->type_argv [param_num]->data.generic_param;
2472 /*param must be a MVAR */
2473 if (!ctx->generic_context->method_inst || ctx->generic_context->method_inst->type_argc <= param_num) {
2474 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic method argument %d", param_num));
2475 return NULL;
2477 return ctx->generic_context->method_inst->type_argv [param_num]->data.generic_param;
2481 static gboolean
2482 recursive_boxed_constraint_type_check (VerifyContext *ctx, MonoType *type, MonoClass *constraint_class, int recursion_level)
2484 MonoType *constraint_type = m_class_get_byval_arg (constraint_class);
2485 if (recursion_level <= 0)
2486 return FALSE;
2488 if (verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (constraint_type), FALSE))
2489 return TRUE;
2491 if (mono_type_is_generic_argument (constraint_type)) {
2492 MonoGenericParam *param = get_generic_param (ctx, constraint_type);
2493 MonoClass **klass;
2494 if (!param)
2495 return FALSE;
2496 for (klass = mono_generic_param_info (param)->constraints; klass && *klass; ++klass) {
2497 if (recursive_boxed_constraint_type_check (ctx, type, *klass, recursion_level - 1))
2498 return TRUE;
2501 return FALSE;
2504 /**
2505 * is_compatible_boxed_valuetype:
2507 * Returns: TRUE if @candidate / @stack is a valid boxed valuetype.
2509 * @type The source type. It it tested to be of the proper type.
2510 * @candidate type of the boxed valuetype.
2511 * @stack stack slot of the boxed valuetype, separate from @candidade since one could be changed before calling this function
2512 * @strict if TRUE candidate must be boxed compatible to the target type
2515 static gboolean
2516 is_compatible_boxed_valuetype (VerifyContext *ctx, MonoType *type, MonoType *candidate, ILStackDesc *stack, gboolean strict)
2518 if (!stack_slot_is_boxed_value (stack))
2519 return FALSE;
2520 if (type->byref || candidate->byref)
2521 return FALSE;
2523 if (mono_type_is_generic_argument (candidate)) {
2524 MonoGenericParam *param = get_generic_param (ctx, candidate);
2525 MonoClass **klass;
2526 if (!param)
2527 return FALSE;
2529 for (klass = mono_generic_param_info (param)->constraints; klass && *klass; ++klass) {
2530 /*256 should be enough since there can't be more than 255 generic arguments.*/
2531 if (recursive_boxed_constraint_type_check (ctx, type, *klass, 256))
2532 return TRUE;
2536 if (mono_type_is_generic_argument (type))
2537 return FALSE;
2539 if (!strict)
2540 return TRUE;
2542 return MONO_TYPE_IS_REFERENCE (type) && verifier_class_is_assignable_from (mono_class_from_mono_type_internal (type), mono_class_from_mono_type_internal (candidate));
2545 static int
2546 verify_stack_type_compatibility_full (VerifyContext *ctx, MonoType *type, ILStackDesc *stack, gboolean drop_byref, gboolean valuetype_must_be_boxed)
2548 MonoType *candidate = mono_type_from_stack_slot (stack);
2549 if (MONO_TYPE_IS_REFERENCE (type) && !type->byref && stack_slot_is_null_literal (stack))
2550 return TRUE;
2552 if (is_compatible_boxed_valuetype (ctx, type, candidate, stack, TRUE))
2553 return TRUE;
2555 if (valuetype_must_be_boxed && !stack_slot_is_boxed_value (stack) && !MONO_TYPE_IS_REFERENCE (candidate))
2556 return FALSE;
2558 if (!valuetype_must_be_boxed && stack_slot_is_boxed_value (stack))
2559 return FALSE;
2561 if (drop_byref)
2562 return verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (candidate), FALSE);
2564 /* Handle how Roslyn emit fixed statements by encoding it as byref */
2565 if (type->byref && candidate->byref && (type->type == MONO_TYPE_I) && !mono_type_is_reference (candidate)) {
2566 if (!IS_STRICT_MODE (ctx))
2567 return TRUE;
2570 return verify_type_compatibility_full (ctx, type, candidate, FALSE);
2573 static int
2574 verify_stack_type_compatibility (VerifyContext *ctx, MonoType *type, ILStackDesc *stack)
2576 return verify_stack_type_compatibility_full (ctx, type, stack, FALSE, FALSE);
2579 static gboolean
2580 mono_delegate_type_equal (MonoType *target, MonoType *candidate)
2582 if (candidate->byref ^ target->byref)
2583 return FALSE;
2585 switch (target->type) {
2586 case MONO_TYPE_VOID:
2587 case MONO_TYPE_I1:
2588 case MONO_TYPE_U1:
2589 case MONO_TYPE_BOOLEAN:
2590 case MONO_TYPE_I2:
2591 case MONO_TYPE_U2:
2592 case MONO_TYPE_CHAR:
2593 case MONO_TYPE_I4:
2594 case MONO_TYPE_U4:
2595 case MONO_TYPE_I8:
2596 case MONO_TYPE_U8:
2597 case MONO_TYPE_R4:
2598 case MONO_TYPE_R8:
2599 case MONO_TYPE_I:
2600 case MONO_TYPE_U:
2601 case MONO_TYPE_STRING:
2602 case MONO_TYPE_TYPEDBYREF:
2603 return candidate->type == target->type;
2605 case MONO_TYPE_PTR:
2606 if (candidate->type != MONO_TYPE_PTR)
2607 return FALSE;
2608 return mono_delegate_type_equal (target->data.type, candidate->data.type);
2610 case MONO_TYPE_FNPTR:
2611 if (candidate->type != MONO_TYPE_FNPTR)
2612 return FALSE;
2613 return mono_delegate_signature_equal (mono_type_get_signature_internal (target), mono_type_get_signature_internal (candidate), FALSE);
2615 case MONO_TYPE_GENERICINST: {
2616 MonoClass *target_klass;
2617 MonoClass *candidate_klass;
2618 target_klass = mono_class_from_mono_type_internal (target);
2619 candidate_klass = mono_class_from_mono_type_internal (candidate);
2620 /*FIXME handle nullables and enum*/
2621 return verifier_class_is_assignable_from (target_klass, candidate_klass);
2623 case MONO_TYPE_OBJECT:
2624 return MONO_TYPE_IS_REFERENCE (candidate);
2626 case MONO_TYPE_CLASS:
2627 return verifier_class_is_assignable_from(target->data.klass, mono_class_from_mono_type_internal (candidate));
2629 case MONO_TYPE_SZARRAY:
2630 if (candidate->type != MONO_TYPE_SZARRAY)
2631 return FALSE;
2632 return verifier_class_is_assignable_from (m_class_get_element_class (mono_class_from_mono_type_internal (target)), m_class_get_element_class (mono_class_from_mono_type_internal (candidate)));
2634 case MONO_TYPE_ARRAY:
2635 if (candidate->type != MONO_TYPE_ARRAY)
2636 return FALSE;
2637 return is_array_type_compatible (target, candidate);
2639 case MONO_TYPE_VALUETYPE:
2640 /*FIXME handle nullables and enum*/
2641 return mono_class_from_mono_type_internal (candidate) == mono_class_from_mono_type_internal (target);
2643 case MONO_TYPE_VAR:
2644 return candidate->type == MONO_TYPE_VAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2645 return FALSE;
2647 case MONO_TYPE_MVAR:
2648 return candidate->type == MONO_TYPE_MVAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2649 return FALSE;
2651 default:
2652 VERIFIER_DEBUG ( printf ("Unknown type %d. Implement me!\n", target->type); );
2653 g_assert_not_reached ();
2654 return FALSE;
2658 static gboolean
2659 mono_delegate_param_equal (MonoType *delegate, MonoType *method)
2661 if (mono_metadata_type_equal_full (delegate, method, TRUE))
2662 return TRUE;
2664 return mono_delegate_type_equal (method, delegate);
2667 static gboolean
2668 mono_delegate_ret_equal (MonoType *delegate, MonoType *method)
2670 if (mono_metadata_type_equal_full (delegate, method, TRUE))
2671 return TRUE;
2673 return mono_delegate_type_equal (delegate, method);
2677 * mono_delegate_signature_equal:
2679 * Compare two signatures in the way expected by delegates.
2681 * This function only exists due to the fact that it should ignore the 'has_this' part of the signature.
2683 * FIXME can this function be eliminated and proper metadata functionality be used?
2685 static gboolean
2686 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn)
2688 int i;
2689 int method_offset = is_static_ldftn ? 1 : 0;
2691 if (delegate_sig->param_count + method_offset != method_sig->param_count)
2692 return FALSE;
2694 if (delegate_sig->call_convention != method_sig->call_convention)
2695 return FALSE;
2697 for (i = 0; i < delegate_sig->param_count; i++) {
2698 MonoType *p1 = delegate_sig->params [i];
2699 MonoType *p2 = method_sig->params [i + method_offset];
2701 if (!mono_delegate_param_equal (p1, p2))
2702 return FALSE;
2705 if (!mono_delegate_ret_equal (delegate_sig->ret, method_sig->ret))
2706 return FALSE;
2708 return TRUE;
2711 gboolean
2712 mono_verifier_is_signature_compatible (MonoMethodSignature *target, MonoMethodSignature *candidate)
2714 return mono_delegate_signature_equal (target, candidate, FALSE);
2718 * verify_ldftn_delegate:
2720 * Verify properties of ldftn based delegates.
2722 static void
2723 verify_ldftn_delegate (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2725 MonoMethod *method = funptr->method;
2727 /*ldftn non-final virtuals only allowed if method is not static,
2728 * the object is a this arg (comes from a ldarg.0), and there is no starg.0.
2729 * This rules doesn't apply if the object on stack is a boxed valuetype.
2731 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !mono_class_is_sealed (method->klass) && !stack_slot_is_boxed_value (value)) {
2732 /*A stdarg 0 must not happen, we fail here only in fail fast mode to avoid double error reports*/
2733 if (IS_FAIL_FAST_MODE (ctx) && ctx->has_this_store)
2734 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at 0x%04x", ctx->ip_offset));
2736 /*current method must not be static*/
2737 if (ctx->method->flags & METHOD_ATTRIBUTE_STATIC)
2738 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function at 0x%04x", ctx->ip_offset));
2740 /*value is the this pointer, loaded using ldarg.0 */
2741 if (!stack_slot_is_this_pointer (value))
2742 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));
2744 ctx->code [ctx->ip_offset].flags |= IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL;
2749 * verify_delegate_compatibility:
2751 * Verify delegate creation sequence.
2754 static void
2755 verify_delegate_compatibility (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2757 #define IS_VALID_OPCODE(offset, opcode) (ip [ip_offset - offset] == opcode && (ctx->code [ip_offset - offset].flags & IL_CODE_FLAG_SEEN))
2758 #define IS_LOAD_FUN_PTR(kind) (IS_VALID_OPCODE (6, CEE_PREFIX1) && ip [ip_offset - 5] == kind)
2760 MonoMethod *invoke, *method;
2761 const guint8 *ip = ctx->header->code;
2762 guint32 ip_offset = ctx->ip_offset;
2763 gboolean is_static_ldftn = FALSE, is_first_arg_bound = FALSE;
2765 if (stack_slot_get_type (funptr) != TYPE_PTR || !funptr->method) {
2766 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid function pointer parameter for delegate constructor at 0x%04x", ctx->ip_offset));
2767 return;
2770 invoke = mono_get_delegate_invoke_internal (delegate);
2771 method = funptr->method;
2773 if (!method || !mono_method_signature_internal (method)) {
2774 char *name = mono_type_get_full_name (delegate);
2775 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid method on stack to create delegate %s construction at 0x%04x", name, ctx->ip_offset));
2776 g_free (name);
2777 return;
2780 if (!invoke || !mono_method_signature_internal (invoke)) {
2781 char *name = mono_type_get_full_name (delegate);
2782 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Delegate type %s with bad Invoke method at 0x%04x", name, ctx->ip_offset));
2783 g_free (name);
2784 return;
2787 is_static_ldftn = (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) && method->flags & METHOD_ATTRIBUTE_STATIC;
2789 if (is_static_ldftn)
2790 is_first_arg_bound = mono_method_signature_internal (invoke)->param_count + 1 == mono_method_signature_internal (method)->param_count;
2792 if (!mono_delegate_signature_equal (mono_method_signature_internal (invoke), mono_method_signature_internal (method), is_first_arg_bound)) {
2793 char *fun_sig = mono_signature_get_desc (mono_method_signature_internal (method), FALSE);
2794 char *invoke_sig = mono_signature_get_desc (mono_method_signature_internal (invoke), FALSE);
2795 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));
2796 g_free (fun_sig);
2797 g_free (invoke_sig);
2801 * Delegate code sequences:
2802 * [-6] ldftn token
2803 * newobj ...
2806 * [-7] dup
2807 * [-6] ldvirtftn token
2808 * newobj ...
2810 * ldftn sequence:*/
2811 if (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) {
2812 verify_ldftn_delegate (ctx, delegate, value, funptr);
2813 } else if (ip_offset > 6 && IS_VALID_OPCODE (7, CEE_DUP) && IS_LOAD_FUN_PTR (CEE_LDVIRTFTN)) {
2814 ctx->code [ip_offset - 6].flags |= IL_CODE_DELEGATE_SEQUENCE;
2815 }else {
2816 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid code sequence for delegate creation at 0x%04x", ctx->ip_offset));
2818 ctx->code [ip_offset].flags |= IL_CODE_DELEGATE_SEQUENCE;
2820 //general tests
2821 if (is_first_arg_bound) {
2822 if (mono_method_signature_internal (method)->param_count == 0 || !verify_stack_type_compatibility_full (ctx, mono_method_signature_internal (method)->params [0], value, FALSE, TRUE))
2823 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2824 } else {
2825 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
2826 if (!stack_slot_is_null_literal (value))
2827 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Non-null this args used with static function for delegate creation at 0x%04x", ctx->ip_offset));
2828 } else {
2829 if (!verify_stack_type_compatibility_full (ctx, m_class_get_byval_arg (method->klass), value, FALSE, TRUE) && !stack_slot_is_null_literal (value))
2830 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2834 if (stack_slot_get_type (value) != TYPE_COMPLEX)
2835 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid first parameter for delegate creation at 0x%04x", ctx->ip_offset));
2837 #undef IS_VALID_OPCODE
2838 #undef IS_LOAD_FUN_PTR
2841 static gboolean
2842 is_this_arg_of_struct_instance_method (unsigned int arg, VerifyContext *ctx)
2844 if (arg != 0)
2845 return FALSE;
2846 if (ctx->method->flags & METHOD_ATTRIBUTE_STATIC)
2847 return FALSE;
2848 if (!m_class_is_valuetype (ctx->method->klass))
2849 return FALSE;
2850 return TRUE;
2853 /* implement the opcode checks*/
2854 static void
2855 push_arg (VerifyContext *ctx, unsigned int arg, int take_addr)
2857 ILStackDesc *top;
2859 if (arg >= ctx->max_args) {
2860 if (take_addr)
2861 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2862 else {
2863 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2864 if (check_overflow (ctx)) //FIXME: what sane value could we ever push?
2865 stack_push_val (ctx, TYPE_I4, mono_get_int32_type ());
2867 } else if (check_overflow (ctx)) {
2868 /*We must let the value be pushed, otherwise we would get an underflow error*/
2869 check_unverifiable_type (ctx, ctx->params [arg]);
2870 if (ctx->params [arg]->byref && take_addr)
2871 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2872 top = stack_push (ctx);
2873 if (!set_stack_value (ctx, top, ctx->params [arg], take_addr))
2874 return;
2876 if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC)) {
2877 if (take_addr)
2878 ctx->has_this_store = TRUE;
2879 else
2880 top->stype |= THIS_POINTER_MASK;
2881 if (mono_method_is_constructor (ctx->method) && !ctx->super_ctor_called && !m_class_is_valuetype (ctx->method->klass))
2882 top->stype |= UNINIT_THIS_MASK;
2884 if (!take_addr && ctx->params [arg]->byref && !is_this_arg_of_struct_instance_method (arg, ctx))
2885 top->stype |= SAFE_BYREF_MASK;
2889 static void
2890 push_local (VerifyContext *ctx, guint32 arg, int take_addr)
2892 if (arg >= ctx->num_locals) {
2893 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local %d", arg + 1));
2894 } else if (check_overflow (ctx)) {
2895 /*We must let the value be pushed, otherwise we would get an underflow error*/
2896 check_unverifiable_type (ctx, ctx->locals [arg]);
2897 if (ctx->locals [arg]->byref && take_addr)
2898 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2900 ILStackDesc *value = stack_push (ctx);
2901 set_stack_value (ctx, value, ctx->locals [arg], take_addr);
2902 if (local_is_safe_byref (ctx, arg))
2903 value->stype |= SAFE_BYREF_MASK;
2907 static void
2908 store_arg (VerifyContext *ctx, guint32 arg)
2910 ILStackDesc *value;
2912 if (arg >= ctx->max_args) {
2913 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", arg + 1, ctx->ip_offset));
2914 if (check_underflow (ctx, 1))
2915 stack_pop (ctx);
2916 return;
2919 if (check_underflow (ctx, 1)) {
2920 value = stack_pop (ctx);
2921 if (!verify_stack_type_compatibility (ctx, ctx->params [arg], value)) {
2922 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in argument store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
2925 if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC))
2926 ctx->has_this_store = 1;
2929 static void
2930 store_local (VerifyContext *ctx, guint32 arg)
2932 ILStackDesc *value;
2933 if (arg >= ctx->num_locals) {
2934 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", arg + 1, ctx->ip_offset));
2935 return;
2938 /*TODO verify definite assigment */
2939 if (!check_underflow (ctx, 1))
2940 return;
2942 value = stack_pop (ctx);
2943 if (ctx->locals [arg]->byref) {
2944 if (stack_slot_is_managed_mutability_pointer (value))
2945 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));
2947 if (local_is_safe_byref (ctx, arg) && !stack_slot_is_safe_byref (value))
2948 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));
2950 if (stack_slot_is_safe_byref (value) && !local_is_unsafe_byref (ctx, arg))
2951 ctx->locals_verification_state [arg] |= SAFE_BYREF_LOCAL;
2953 if (!stack_slot_is_safe_byref (value))
2954 ctx->locals_verification_state [arg] |= UNSAFE_BYREF_LOCAL;
2957 if (!verify_stack_type_compatibility (ctx, ctx->locals [arg], value)) {
2958 char *expected = mono_type_full_name (ctx->locals [arg]);
2959 char *found = stack_slot_full_name (value);
2960 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type '%s' on stack cannot be stored to local %d with type '%s' at 0x%04x",
2961 found,
2962 arg,
2963 expected,
2964 ctx->ip_offset));
2965 g_free (expected);
2966 g_free (found);
2970 /*FIXME add and sub needs special care here*/
2971 static void
2972 do_binop (VerifyContext *ctx, unsigned int opcode, const unsigned char table [TYPE_MAX][TYPE_MAX])
2974 ILStackDesc *a, *b, *top;
2975 int idxa, idxb, complexMerge = 0;
2976 unsigned char res;
2978 if (!check_underflow (ctx, 2))
2979 return;
2980 b = stack_pop (ctx);
2981 a = stack_pop (ctx);
2983 idxa = stack_slot_get_underlying_type (a);
2984 if (stack_slot_is_managed_pointer (a)) {
2985 idxa = TYPE_PTR;
2986 complexMerge = 1;
2989 idxb = stack_slot_get_underlying_type (b);
2990 if (stack_slot_is_managed_pointer (b)) {
2991 idxb = TYPE_PTR;
2992 complexMerge = 2;
2995 --idxa;
2996 --idxb;
2997 res = table [idxa][idxb];
2999 VERIFIER_DEBUG ( printf ("binop res %d\n", res); );
3000 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
3002 top = stack_push (ctx);
3003 if (res == TYPE_INV) {
3004 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)));
3005 copy_stack_value (top, a);
3006 return;
3009 if (res & NON_VERIFIABLE_RESULT) {
3010 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)));
3012 res = res & ~NON_VERIFIABLE_RESULT;
3015 if (complexMerge && res == TYPE_PTR) {
3016 if (complexMerge == 1)
3017 copy_stack_value (top, a);
3018 else if (complexMerge == 2)
3019 copy_stack_value (top, b);
3021 * There is no need to merge the type of two pointers.
3022 * The only valid operation is subtraction, that returns a native
3023 * int as result and can be used with any 2 pointer kinds.
3024 * This is valid acording to Patition III 1.1.4
3026 } else
3027 top->stype = res;
3032 static void
3033 do_boolean_branch_op (VerifyContext *ctx, int delta)
3035 int target = ctx->ip_offset + delta;
3036 ILStackDesc *top;
3038 VERIFIER_DEBUG ( printf ("boolean branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
3040 if (target < 0 || target >= ctx->code_size) {
3041 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Boolean branch target out of code at 0x%04x", ctx->ip_offset));
3042 return;
3045 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
3046 case 1:
3047 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3048 break;
3049 case 2:
3050 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3051 return;
3054 ctx->target = target;
3056 if (!check_underflow (ctx, 1))
3057 return;
3059 top = stack_pop (ctx);
3060 if (!is_valid_bool_arg (top))
3061 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));
3063 check_unmanaged_pointer (ctx, top);
3066 static gboolean
3067 stack_slot_is_complex_type_not_reference_type (ILStackDesc *slot)
3069 return stack_slot_get_type (slot) == TYPE_COMPLEX && !MONO_TYPE_IS_REFERENCE (slot->type) && !stack_slot_is_boxed_value (slot);
3072 static gboolean
3073 stack_slot_is_reference_value (ILStackDesc *slot)
3075 return stack_slot_get_type (slot) == TYPE_COMPLEX && (MONO_TYPE_IS_REFERENCE (slot->type) || stack_slot_is_boxed_value (slot));
3078 static void
3079 do_branch_op (VerifyContext *ctx, signed int delta, const unsigned char table [TYPE_MAX][TYPE_MAX])
3081 ILStackDesc *a, *b;
3082 int idxa, idxb;
3083 unsigned char res;
3084 int target = ctx->ip_offset + delta;
3086 VERIFIER_DEBUG ( printf ("branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
3088 if (target < 0 || target >= ctx->code_size) {
3089 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
3090 return;
3093 switch (is_valid_cmp_branch_instruction (ctx->header, ctx->ip_offset, target)) {
3094 case 1: /*FIXME use constants and not magic numbers.*/
3095 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3096 break;
3097 case 2:
3098 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3099 return;
3102 ctx->target = target;
3104 if (!check_underflow (ctx, 2))
3105 return;
3107 b = stack_pop (ctx);
3108 a = stack_pop (ctx);
3110 idxa = stack_slot_get_underlying_type (a);
3111 if (stack_slot_is_managed_pointer (a))
3112 idxa = TYPE_PTR;
3114 idxb = stack_slot_get_underlying_type (b);
3115 if (stack_slot_is_managed_pointer (b))
3116 idxb = TYPE_PTR;
3118 if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
3119 res = TYPE_INV;
3120 } else {
3121 --idxa;
3122 --idxb;
3123 res = table [idxa][idxb];
3126 VERIFIER_DEBUG ( printf ("branch res %d\n", res); );
3127 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
3129 if (res == TYPE_INV) {
3130 CODE_NOT_VERIFIABLE (ctx,
3131 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));
3132 } else if (res & NON_VERIFIABLE_RESULT) {
3133 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));
3134 res = res & ~NON_VERIFIABLE_RESULT;
3138 static void
3139 do_cmp_op (VerifyContext *ctx, const unsigned char table [TYPE_MAX][TYPE_MAX], guint32 opcode)
3141 ILStackDesc *a, *b;
3142 int idxa, idxb;
3143 unsigned char res;
3145 if (!check_underflow (ctx, 2))
3146 return;
3147 b = stack_pop (ctx);
3148 a = stack_pop (ctx);
3150 if (opcode == CEE_CGT_UN) {
3151 if ((stack_slot_is_reference_value (a) && stack_slot_is_null_literal (b)) ||
3152 (stack_slot_is_reference_value (b) && stack_slot_is_null_literal (a))) {
3153 stack_push_val (ctx, TYPE_I4, mono_get_int32_type ());
3154 return;
3158 idxa = stack_slot_get_underlying_type (a);
3159 if (stack_slot_is_managed_pointer (a))
3160 idxa = TYPE_PTR;
3162 idxb = stack_slot_get_underlying_type (b);
3163 if (stack_slot_is_managed_pointer (b))
3164 idxb = TYPE_PTR;
3166 if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
3167 res = TYPE_INV;
3168 } else {
3169 --idxa;
3170 --idxb;
3171 res = table [idxa][idxb];
3174 if(res == TYPE_INV) {
3175 char *left_type = stack_slot_full_name (a);
3176 char *right_type = stack_slot_full_name (b);
3177 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));
3178 g_free (left_type);
3179 g_free (right_type);
3180 } else if (res & NON_VERIFIABLE_RESULT) {
3181 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));
3182 res = res & ~NON_VERIFIABLE_RESULT;
3184 stack_push_val (ctx, TYPE_I4, mono_get_int32_type ());
3187 static void
3188 do_ret (VerifyContext *ctx)
3190 MonoType *ret = ctx->signature->ret;
3191 VERIFIER_DEBUG ( printf ("checking ret\n"); );
3192 if (ret->type != MONO_TYPE_VOID) {
3193 ILStackDesc *top;
3194 if (!check_underflow (ctx, 1))
3195 return;
3197 top = stack_pop(ctx);
3199 if (!verify_stack_type_compatibility (ctx, ctx->signature->ret, top)) {
3200 char *ret_type = mono_type_full_name (ctx->signature->ret);
3201 char *stack_type = stack_slot_full_name (top);
3202 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));
3203 g_free (stack_type);
3204 g_free (ret_type);
3205 return;
3208 if (ret->byref && !stack_slot_is_safe_byref (top))
3209 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));
3211 if (ret->type == MONO_TYPE_TYPEDBYREF || mono_type_is_value_type (ret, "System", "ArgIterator") || mono_type_is_value_type (ret, "System", "RuntimeArgumentHandle"))
3212 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method returns byref, TypedReference, ArgIterator or RuntimeArgumentHandle at 0x%04x", ctx->ip_offset));
3215 if (ctx->eval.size > 0) {
3216 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack not empty (%d) after ret at 0x%04x", ctx->eval.size, ctx->ip_offset));
3218 if (in_any_block (ctx->header, ctx->ip_offset))
3219 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ret cannot escape exception blocks at 0x%04x", ctx->ip_offset));
3223 * 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.
3224 * This is illegal but mono_get_method_full decoded it.
3225 * TODO handle calling .ctor outside one or calling the .ctor for other class but super
3227 static void
3228 do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual_)
3230 ERROR_DECL (error);
3231 int param_count, i;
3232 MonoMethodSignature *sig;
3233 ILStackDesc *value;
3234 MonoMethod *method;
3235 gboolean virt_check_this = FALSE;
3236 gboolean constrained = ctx->prefix_set & PREFIX_CONSTRAINED;
3238 if (!(method = verifier_load_method (ctx, method_token, virtual_ ? "callvirt" : "call")))
3239 return;
3241 if (virtual_) {
3242 CLEAR_PREFIX (ctx, PREFIX_CONSTRAINED);
3244 if (m_class_is_valuetype (method->klass)) // && !constrained ???
3245 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with valuetype method at 0x%04x", ctx->ip_offset));
3247 if ((method->flags & METHOD_ATTRIBUTE_STATIC))
3248 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with static method at 0x%04x", ctx->ip_offset));
3250 } else {
3251 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
3252 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use call with an abstract method at 0x%04x", ctx->ip_offset));
3254 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !mono_class_is_sealed (method->klass)) {
3255 virt_check_this = TRUE;
3256 ctx->code [ctx->ip_offset].flags |= IL_CODE_CALL_NONFINAL_VIRTUAL;
3260 if (!(sig = mono_method_get_signature_checked (method, ctx->image, method_token, ctx->generic_context, error))) {
3261 mono_error_cleanup (error);
3262 sig = mono_method_get_signature_checked (method, ctx->image, method_token, NULL, error);
3265 if (!sig) {
3266 char *name = mono_type_get_full_name (method->klass);
3267 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)));
3268 mono_error_cleanup (error);
3269 g_free (name);
3270 return;
3273 param_count = sig->param_count + sig->hasthis;
3274 if (!check_underflow (ctx, param_count))
3275 return;
3277 gboolean is_safe_byref_call = TRUE;
3279 for (i = sig->param_count - 1; i >= 0; --i) {
3280 VERIFIER_DEBUG ( printf ("verifying argument %d\n", i); );
3281 value = stack_pop (ctx);
3282 if (!verify_stack_type_compatibility (ctx, sig->params[i], value)) {
3283 char *stack_name = stack_slot_full_name (value);
3284 char *sig_name = mono_type_full_name (sig->params [i]);
3285 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));
3286 g_free (stack_name);
3287 g_free (sig_name);
3290 if (stack_slot_is_managed_mutability_pointer (value))
3291 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));
3293 if ((ctx->prefix_set & PREFIX_TAIL) && stack_slot_is_managed_pointer (value)) {
3294 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));
3295 return;
3297 if (stack_slot_is_managed_pointer (value) && !stack_slot_is_safe_byref (value))
3298 is_safe_byref_call = FALSE;
3301 if (sig->hasthis) {
3302 MonoType *type = m_class_get_byval_arg (method->klass);
3303 ILStackDesc copy;
3305 if (mono_method_is_constructor (method) && !m_class_is_valuetype (method->klass)) {
3306 if (IS_STRICT_MODE (ctx) && !mono_method_is_constructor (ctx->method))
3307 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor outside one at 0x%04x", ctx->ip_offset));
3308 if (IS_STRICT_MODE (ctx) && method->klass != m_class_get_parent (ctx->method->klass) && method->klass != ctx->method->klass)
3309 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));
3311 ctx->super_ctor_called = TRUE;
3312 value = stack_pop_safe (ctx);
3313 if (IS_STRICT_MODE (ctx) && (value->stype & THIS_POINTER_MASK) != THIS_POINTER_MASK)
3314 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid 'this ptr' argument for constructor at 0x%04x", ctx->ip_offset));
3315 if (!(value->stype & UNINIT_THIS_MASK))
3316 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Calling the base constructor on an initialized this pointer at 0x%04x", ctx->ip_offset));
3317 } else {
3318 value = stack_pop (ctx);
3321 copy_stack_value (&copy, value);
3322 //TODO we should extract this to a 'drop_byref_argument' and use everywhere
3323 //Other parts of the code suffer from the same issue of
3324 copy.type = mono_type_get_type_byval (copy.type);
3325 copy.stype &= ~POINTER_MASK;
3327 if (virt_check_this && !stack_slot_is_this_pointer (value) && !(m_class_is_valuetype (method->klass) || stack_slot_is_boxed_value (value)))
3328 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));
3330 if (constrained && virtual_) {
3331 if (!stack_slot_is_managed_pointer (value))
3332 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object is not a managed pointer for a constrained call at 0x%04x", ctx->ip_offset));
3333 if (!mono_metadata_type_equal_full (mono_type_get_type_byval (value->type), mono_type_get_underlying_type (ctx->constrained_type), TRUE))
3334 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object not compatible with constrained type at 0x%04x", ctx->ip_offset));
3335 copy.stype |= BOXED_MASK;
3336 copy.type = ctx->constrained_type;
3337 } else {
3338 if (stack_slot_is_managed_pointer (value) && !m_class_is_valuetype (mono_class_from_mono_type_internal (value->type)))
3339 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));
3341 if (!virtual_ && m_class_is_valuetype (mono_class_from_mono_type_internal (value->type)) && !m_class_is_valuetype (method->klass) && !stack_slot_is_boxed_value (value))
3342 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a valuetype baseclass at 0x%04x", ctx->ip_offset));
3344 if (virtual_ && m_class_is_valuetype (mono_class_from_mono_type_internal (value->type)) && !stack_slot_is_boxed_value (value))
3345 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a valuetype with callvirt at 0x%04x", ctx->ip_offset));
3347 if (m_class_is_valuetype (method->klass) && (stack_slot_is_boxed_value (value) || !stack_slot_is_managed_pointer (value)))
3348 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));
3350 if (!verify_stack_type_compatibility (ctx, type, &copy)) {
3351 char *expected = mono_type_full_name (type);
3352 char *effective = stack_slot_full_name (&copy);
3353 char *method_name = mono_method_full_name (method, TRUE);
3354 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",
3355 expected, effective, method_name, ctx->ip_offset));
3356 g_free (method_name);
3357 g_free (effective);
3358 g_free (expected);
3361 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, mono_class_from_mono_type_internal (value->type))) {
3362 char *name = mono_method_full_name (method, TRUE);
3363 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3364 g_free (name);
3367 } else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
3368 char *name = mono_method_full_name (method, TRUE);
3369 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3370 g_free (name);
3373 if (sig->ret->type != MONO_TYPE_VOID) {
3374 if (!mono_type_is_valid_in_context (ctx, sig->ret))
3375 return;
3377 if (check_overflow (ctx)) {
3378 value = stack_push (ctx);
3379 set_stack_value (ctx, value, sig->ret, FALSE);
3380 if ((ctx->prefix_set & PREFIX_READONLY) && m_class_get_rank (method->klass) && !strcmp (method->name, "Address")) {
3381 ctx->prefix_set &= ~PREFIX_READONLY;
3382 value->stype |= CMMP_MASK;
3384 if (sig->ret->byref && is_safe_byref_call)
3385 value->stype |= SAFE_BYREF_MASK;
3389 if ((ctx->prefix_set & PREFIX_TAIL)) {
3390 if (!mono_delegate_ret_equal (mono_method_signature_internal (ctx->method)->ret, sig->ret))
3391 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call with incompatible return type at 0x%04x", ctx->ip_offset));
3392 if (ctx->header->code [ctx->ip_offset + 5] != CEE_RET)
3393 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call not followed by ret at 0x%04x", ctx->ip_offset));
3398 static void
3399 do_push_static_field (VerifyContext *ctx, int token, gboolean take_addr)
3401 MonoClassField *field;
3402 MonoClass *klass;
3403 if (!check_overflow (ctx))
3404 return;
3405 if (!take_addr)
3406 CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3408 if (!(field = verifier_load_field (ctx, token, &klass, take_addr ? "ldsflda" : "ldsfld")))
3409 return;
3411 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3412 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load non static field at 0x%04x", ctx->ip_offset));
3413 return;
3415 /*taking the address of initonly field only works from the static constructor */
3416 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3417 !(field->parent == ctx->method->klass && (ctx->method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_STATIC)) && !strcmp (".cctor", ctx->method->name)))
3418 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
3420 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3421 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3423 ILStackDesc *value = stack_push (ctx);
3424 set_stack_value (ctx, value, field->type, take_addr);
3425 if (take_addr)
3426 value->stype |= SAFE_BYREF_MASK;
3429 static void
3430 do_store_static_field (VerifyContext *ctx, int token) {
3431 MonoClassField *field;
3432 MonoClass *klass;
3433 ILStackDesc *value;
3434 CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3436 if (!check_underflow (ctx, 1))
3437 return;
3439 value = stack_pop (ctx);
3441 if (!(field = verifier_load_field (ctx, token, &klass, "stsfld")))
3442 return;
3444 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3445 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store non static field at 0x%04x", ctx->ip_offset));
3446 return;
3449 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3450 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type in store static field at 0x%04x", ctx->ip_offset));
3451 return;
3454 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3455 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3457 if (!verify_stack_type_compatibility (ctx, field->type, value)) {
3458 char *stack_name = stack_slot_full_name (value);
3459 char *field_name = mono_type_full_name (field->type);
3460 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type in static field store expected '%s' but found '%s' at 0x%04x",
3461 field_name, stack_name, ctx->ip_offset));
3462 g_free (field_name);
3463 g_free (stack_name);
3467 static gboolean
3468 check_is_valid_type_for_field_ops (VerifyContext *ctx, int token, ILStackDesc *obj, MonoClassField **ret_field, const char *opcode)
3470 MonoClassField *field;
3471 MonoClass *klass;
3472 gboolean is_pointer;
3474 /*must be a reference type, a managed pointer, an unamanaged pointer, or a valuetype*/
3475 if (!(field = verifier_load_field (ctx, token, &klass, opcode)))
3476 return FALSE;
3478 *ret_field = field;
3479 //the value on stack is going to be used as a pointer
3480 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)));
3482 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3483 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type at 0x%04x", ctx->ip_offset));
3484 return FALSE;
3486 g_assert (obj->type);
3488 /*The value on the stack must be a subclass of the defining type of the field*/
3489 /* we need to check if we can load the field from the stack value*/
3490 if (is_pointer) {
3491 if (stack_slot_get_underlying_type (obj) == TYPE_NATIVE_INT)
3492 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Native int is not a verifiable type to reference a field at 0x%04x", ctx->ip_offset));
3494 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3495 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3496 } else {
3497 if (!m_class_is_valuetype (field->parent) && stack_slot_is_managed_pointer (obj))
3498 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));
3500 /*a value type can be loaded from a value or a managed pointer, but not a boxed object*/
3501 if (m_class_is_valuetype (field->parent) && stack_slot_is_boxed_value (obj))
3502 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));
3504 if (!stack_slot_is_null_literal (obj) && !verify_stack_type_compatibility_full (ctx, m_class_get_byval_arg (field->parent), obj, TRUE, FALSE)) {
3505 char *found = stack_slot_full_name (obj);
3506 char *expected = mono_type_full_name (m_class_get_byval_arg (field->parent));
3507 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));
3508 g_free (found);
3509 g_free (expected);
3512 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, mono_class_from_mono_type_internal (obj->type)))
3513 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3516 check_unmanaged_pointer (ctx, obj);
3517 return TRUE;
3520 static void
3521 do_push_field (VerifyContext *ctx, int token, gboolean take_addr)
3523 ILStackDesc *obj;
3524 MonoClassField *field;
3525 gboolean is_safe_byref = FALSE;
3527 if (!take_addr)
3528 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3530 if (!check_underflow (ctx, 1))
3531 return;
3532 obj = stack_pop_safe (ctx);
3534 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, take_addr ? "ldflda" : "ldfld"))
3535 return;
3537 if (take_addr && m_class_is_valuetype (field->parent) && !stack_slot_is_managed_pointer (obj))
3538 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a temporary value-type at 0x%04x", ctx->ip_offset));
3540 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3541 !(field->parent == ctx->method->klass && mono_method_is_constructor (ctx->method)))
3542 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
3544 //must do it here cuz stack_push will return the same slot as obj above
3545 is_safe_byref = take_addr && (stack_slot_is_reference_value (obj) || stack_slot_is_safe_byref (obj));
3547 ILStackDesc *value = stack_push (ctx);
3548 set_stack_value (ctx, value, field->type, take_addr);
3550 if (is_safe_byref)
3551 value->stype |= SAFE_BYREF_MASK;
3554 static void
3555 do_store_field (VerifyContext *ctx, int token)
3557 ILStackDesc *value, *obj;
3558 MonoClassField *field;
3559 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3561 if (!check_underflow (ctx, 2))
3562 return;
3564 value = stack_pop (ctx);
3565 obj = stack_pop_safe (ctx);
3567 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, "stfld"))
3568 return;
3570 if (!verify_stack_type_compatibility (ctx, field->type, value))
3571 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in field store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3574 /*TODO proper handle for Nullable<T>*/
3575 static void
3576 do_box_value (VerifyContext *ctx, int klass_token)
3578 ILStackDesc *value;
3579 MonoType *type = get_boxable_mono_type (ctx, klass_token, "box");
3580 MonoClass *klass;
3582 if (!type)
3583 return;
3585 if (!check_underflow (ctx, 1))
3586 return;
3588 value = stack_pop (ctx);
3589 /*box is a nop for reference types*/
3591 if (stack_slot_get_underlying_type (value) == TYPE_COMPLEX && MONO_TYPE_IS_REFERENCE (value->type) && MONO_TYPE_IS_REFERENCE (type)) {
3592 stack_push_stack_val (ctx, value)->stype |= BOXED_MASK;
3593 return;
3597 if (!verify_stack_type_compatibility (ctx, type, value))
3598 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for boxing operation at 0x%04x", ctx->ip_offset));
3600 klass = mono_class_from_mono_type_internal (type);
3601 if (mono_class_is_nullable (klass))
3602 type = m_class_get_byval_arg (mono_class_get_nullable_param_internal (klass));
3603 stack_push_val (ctx, TYPE_COMPLEX | BOXED_MASK, type);
3606 static void
3607 do_unbox_value (VerifyContext *ctx, int klass_token)
3609 ILStackDesc *value;
3610 MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox");
3612 if (!type)
3613 return;
3615 if (!check_underflow (ctx, 1))
3616 return;
3618 if (!m_class_is_valuetype (mono_class_from_mono_type_internal (type)))
3619 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid reference type for unbox at 0x%04x", ctx->ip_offset));
3621 value = stack_pop (ctx);
3623 /*Value should be: a boxed valuetype or a reference type*/
3624 if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3625 (stack_slot_is_boxed_value (value) || !m_class_is_valuetype (mono_class_from_mono_type_internal (value->type)))))
3626 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));
3628 set_stack_value (ctx, value = stack_push (ctx), mono_type_get_type_byref (type), FALSE);
3629 value->stype |= CMMP_MASK;
3632 static void
3633 do_unbox_any (VerifyContext *ctx, int klass_token)
3635 ILStackDesc *value;
3636 MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox.any");
3638 if (!type)
3639 return;
3641 if (!check_underflow (ctx, 1))
3642 return;
3644 value = stack_pop (ctx);
3646 /*Value should be: a boxed valuetype or a reference type*/
3647 if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3648 (stack_slot_is_boxed_value (value) || !m_class_is_valuetype (mono_class_from_mono_type_internal (value->type)))))
3649 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));
3651 set_stack_value (ctx, stack_push (ctx), type, FALSE);
3654 static void
3655 do_unary_math_op (VerifyContext *ctx, int op)
3657 ILStackDesc *value;
3658 if (!check_underflow (ctx, 1))
3659 return;
3660 value = stack_pop (ctx);
3661 switch (stack_slot_get_type (value)) {
3662 case TYPE_I4:
3663 case TYPE_I8:
3664 case TYPE_NATIVE_INT:
3665 break;
3666 case TYPE_R8:
3667 if (op == CEE_NEG)
3668 break;
3669 case TYPE_COMPLEX: /*only enums are ok*/
3670 if (mono_type_is_enum_type (value->type))
3671 break;
3672 default:
3673 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for unary not at 0x%04x", ctx->ip_offset));
3675 stack_push_stack_val (ctx, value);
3678 static void
3679 do_conversion (VerifyContext *ctx, int kind)
3681 ILStackDesc *value;
3682 if (!check_underflow (ctx, 1))
3683 return;
3684 value = stack_pop (ctx);
3686 switch (stack_slot_get_type (value)) {
3687 case TYPE_I4:
3688 case TYPE_I8:
3689 case TYPE_NATIVE_INT:
3690 case TYPE_R8:
3691 break;
3692 default:
3693 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));
3696 switch (kind) {
3697 case TYPE_I4:
3698 stack_push_val (ctx, TYPE_I4, mono_get_int32_type ());
3699 break;
3700 case TYPE_I8:
3701 stack_push_val (ctx,TYPE_I8, m_class_get_byval_arg (mono_defaults.int64_class));
3702 break;
3703 case TYPE_R8:
3704 stack_push_val (ctx, TYPE_R8, m_class_get_byval_arg (mono_defaults.double_class));
3705 break;
3706 case TYPE_NATIVE_INT:
3707 stack_push_val (ctx, TYPE_NATIVE_INT, mono_get_int_type ());
3708 break;
3709 default:
3710 g_error ("unknown type %02x in conversion", kind);
3715 static void
3716 do_load_token (VerifyContext *ctx, int token)
3718 ERROR_DECL (error);
3719 gpointer handle;
3720 MonoClass *handle_class;
3721 if (!check_overflow (ctx))
3722 return;
3724 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
3725 handle = mono_method_get_wrapper_data (ctx->method, token);
3726 handle_class = (MonoClass *)mono_method_get_wrapper_data (ctx->method, token + 1);
3727 if (handle_class == mono_defaults.typehandle_class)
3728 handle = m_class_get_byval_arg ((MonoClass*)handle);
3729 } else {
3730 switch (token & 0xff000000) {
3731 case MONO_TOKEN_TYPE_DEF:
3732 case MONO_TOKEN_TYPE_REF:
3733 case MONO_TOKEN_TYPE_SPEC:
3734 case MONO_TOKEN_FIELD_DEF:
3735 case MONO_TOKEN_METHOD_DEF:
3736 case MONO_TOKEN_METHOD_SPEC:
3737 case MONO_TOKEN_MEMBER_REF:
3738 if (!token_bounds_check (ctx->image, token)) {
3739 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));
3740 return;
3742 break;
3743 default:
3744 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));
3745 return;
3748 handle = mono_ldtoken_checked (ctx->image, token, &handle_class, ctx->generic_context, error);
3751 if (!handle) {
3752 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)));
3753 mono_error_cleanup (error);
3754 return;
3756 if (handle_class == mono_defaults.typehandle_class) {
3757 mono_type_is_valid_in_context (ctx, (MonoType*)handle);
3758 } else if (handle_class == mono_defaults.methodhandle_class) {
3759 mono_method_is_valid_in_context (ctx, (MonoMethod*)handle);
3760 } else if (handle_class == mono_defaults.fieldhandle_class) {
3761 mono_type_is_valid_in_context (ctx, m_class_get_byval_arg (((MonoClassField*)handle)->parent));
3762 } else {
3763 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid ldtoken type %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
3765 stack_push_val (ctx, TYPE_COMPLEX, m_class_get_byval_arg (handle_class));
3768 static void
3769 do_ldobj_value (VerifyContext *ctx, int token)
3771 ILStackDesc *value;
3772 MonoType *type = get_boxable_mono_type (ctx, token, "ldobj");
3773 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3775 if (!type)
3776 return;
3778 if (!check_underflow (ctx, 1))
3779 return;
3781 value = stack_pop (ctx);
3782 if (!stack_slot_is_managed_pointer (value)
3783 && stack_slot_get_type (value) != TYPE_NATIVE_INT
3784 && !(stack_slot_get_type (value) == TYPE_PTR && value->type->type != MONO_TYPE_FNPTR)) {
3785 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid argument %s to ldobj at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3786 return;
3789 if (stack_slot_get_type (value) == TYPE_NATIVE_INT)
3790 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Using native pointer to ldobj at 0x%04x", ctx->ip_offset));
3792 /*We have a byval on the stack, but the comparison must be strict. */
3793 if (!verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (value->type), TRUE))
3794 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldojb operation at 0x%04x", ctx->ip_offset));
3796 set_stack_value (ctx, stack_push (ctx), type, FALSE);
3799 static void
3800 do_stobj (VerifyContext *ctx, int token)
3802 ILStackDesc *dest, *src;
3803 MonoType *type = get_boxable_mono_type (ctx, token, "stobj");
3804 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3806 if (!type)
3807 return;
3809 if (!check_underflow (ctx, 2))
3810 return;
3812 src = stack_pop (ctx);
3813 dest = stack_pop (ctx);
3815 if (stack_slot_is_managed_mutability_pointer (dest))
3816 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stobj at 0x%04x", ctx->ip_offset));
3818 if (!stack_slot_is_managed_pointer (dest))
3819 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of stobj operation at 0x%04x", ctx->ip_offset));
3821 if (stack_slot_is_boxed_value (src) && !MONO_TYPE_IS_REFERENCE (src->type) && !MONO_TYPE_IS_REFERENCE (type))
3822 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));
3824 if (!verify_stack_type_compatibility (ctx, type, src)) {
3825 char *type_name = mono_type_full_name (type);
3826 char *src_name = stack_slot_full_name (src);
3827 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));
3828 g_free (type_name);
3829 g_free (src_name);
3832 if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3833 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of stobj don't match at 0x%04x", ctx->ip_offset));
3836 static void
3837 do_cpobj (VerifyContext *ctx, int token)
3839 ILStackDesc *dest, *src;
3840 MonoType *type = get_boxable_mono_type (ctx, token, "cpobj");
3841 if (!type)
3842 return;
3844 if (!check_underflow (ctx, 2))
3845 return;
3847 src = stack_pop (ctx);
3848 dest = stack_pop (ctx);
3850 if (!stack_slot_is_managed_pointer (src))
3851 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid source of cpobj operation at 0x%04x", ctx->ip_offset));
3853 if (!stack_slot_is_managed_pointer (dest))
3854 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of cpobj operation at 0x%04x", ctx->ip_offset));
3856 if (stack_slot_is_managed_mutability_pointer (dest))
3857 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with cpobj at 0x%04x", ctx->ip_offset));
3859 if (!verify_type_compatibility (ctx, type, mono_type_get_type_byval (src->type)))
3860 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Token and source types of cpobj don't match at 0x%04x", ctx->ip_offset));
3862 if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3863 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of cpobj don't match at 0x%04x", ctx->ip_offset));
3866 static void
3867 do_initobj (VerifyContext *ctx, int token)
3869 ILStackDesc *obj;
3870 MonoType *stack, *type = get_boxable_mono_type (ctx, token, "initobj");
3871 if (!type)
3872 return;
3874 if (!check_underflow (ctx, 1))
3875 return;
3877 obj = stack_pop (ctx);
3879 if (!stack_slot_is_managed_pointer (obj))
3880 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid object address for initobj at 0x%04x", ctx->ip_offset));
3882 if (stack_slot_is_managed_mutability_pointer (obj))
3883 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with initobj at 0x%04x", ctx->ip_offset));
3885 stack = mono_type_get_type_byval (obj->type);
3886 if (MONO_TYPE_IS_REFERENCE (stack)) {
3887 if (!verify_type_compatibility (ctx, stack, type))
3888 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3889 else if (IS_STRICT_MODE (ctx) && !mono_metadata_type_equal (type, stack))
3890 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3891 } else if (!verify_type_compatibility (ctx, stack, type)) {
3892 char *expected_name = mono_type_full_name (type);
3893 char *stack_name = mono_type_full_name (stack);
3895 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));
3896 g_free (expected_name);
3897 g_free (stack_name);
3901 static void
3902 do_newobj (VerifyContext *ctx, int token)
3904 ILStackDesc *value;
3905 int i;
3906 MonoMethodSignature *sig;
3907 MonoMethod *method;
3908 gboolean is_delegate = FALSE;
3910 if (!(method = verifier_load_method (ctx, token, "newobj")))
3911 return;
3913 if (!mono_method_is_constructor (method)) {
3914 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method from token 0x%08x not a constructor at 0x%04x", token, ctx->ip_offset));
3915 return;
3918 if (mono_class_get_flags (method->klass) & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE))
3919 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Trying to instantiate an abstract or interface type at 0x%04x", ctx->ip_offset));
3921 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
3922 char *from = mono_method_full_name (ctx->method, TRUE);
3923 char *to = mono_method_full_name (method, TRUE);
3924 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);
3925 g_free (from);
3926 g_free (to);
3929 //FIXME use mono_method_get_signature_full
3930 sig = mono_method_signature_internal (method);
3931 if (!sig) {
3932 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid constructor signature to newobj at 0x%04x", ctx->ip_offset));
3933 return;
3936 if (!sig->hasthis) {
3937 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid constructor signature missing hasthis at 0x%04x", ctx->ip_offset));
3938 return;
3941 if (!check_underflow (ctx, sig->param_count))
3942 return;
3944 is_delegate = m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class;
3946 if (is_delegate) {
3947 ILStackDesc *funptr;
3948 //first arg is object, second arg is fun ptr
3949 if (sig->param_count != 2) {
3950 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid delegate constructor at 0x%04x", ctx->ip_offset));
3951 return;
3953 funptr = stack_pop (ctx);
3954 value = stack_pop (ctx);
3955 verify_delegate_compatibility (ctx, method->klass, value, funptr);
3956 } else {
3957 for (i = sig->param_count - 1; i >= 0; --i) {
3958 VERIFIER_DEBUG ( printf ("verifying constructor argument %d\n", i); );
3959 value = stack_pop (ctx);
3960 if (!verify_stack_type_compatibility (ctx, sig->params [i], value)) {
3961 char *stack_name = stack_slot_full_name (value);
3962 char *sig_name = mono_type_full_name (sig->params [i]);
3963 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));
3964 g_free (stack_name);
3965 g_free (sig_name);
3968 if (stack_slot_is_managed_mutability_pointer (value))
3969 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer as argument of newobj at 0x%04x", ctx->ip_offset));
3973 if (check_overflow (ctx))
3974 set_stack_value (ctx, stack_push (ctx), m_class_get_byval_arg (method->klass), FALSE);
3977 static void
3978 do_cast (VerifyContext *ctx, int token, const char *opcode) {
3979 ILStackDesc *value;
3980 MonoType *type;
3981 gboolean is_boxed;
3982 gboolean do_box;
3984 if (!check_underflow (ctx, 1))
3985 return;
3987 if (!(type = get_boxable_mono_type (ctx, token, opcode)))
3988 return;
3990 if (type->byref) {
3991 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid %s type at 0x%04x", opcode, ctx->ip_offset));
3992 return;
3995 value = stack_pop (ctx);
3996 is_boxed = stack_slot_is_boxed_value (value);
3998 if (stack_slot_is_managed_pointer (value))
3999 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
4000 else if (!MONO_TYPE_IS_REFERENCE (value->type) && !is_boxed) {
4001 char *name = stack_slot_full_name (value);
4002 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));
4003 g_free (name);
4006 switch (value->type->type) {
4007 case MONO_TYPE_FNPTR:
4008 case MONO_TYPE_PTR:
4009 case MONO_TYPE_TYPEDBYREF:
4010 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
4011 default:
4012 break;
4015 do_box = is_boxed || mono_type_is_generic_argument(type) || m_class_is_valuetype (mono_class_from_mono_type_internal (type));
4016 stack_push_val (ctx, TYPE_COMPLEX | (do_box ? BOXED_MASK : 0), type);
4019 static MonoType *
4020 mono_type_from_opcode (int opcode) {
4021 switch (opcode) {
4022 case CEE_LDIND_I1:
4023 case CEE_LDIND_U1:
4024 case CEE_STIND_I1:
4025 case CEE_LDELEM_I1:
4026 case CEE_LDELEM_U1:
4027 case CEE_STELEM_I1:
4028 return m_class_get_byval_arg (mono_defaults.sbyte_class);
4030 case CEE_LDIND_I2:
4031 case CEE_LDIND_U2:
4032 case CEE_STIND_I2:
4033 case CEE_LDELEM_I2:
4034 case CEE_LDELEM_U2:
4035 case CEE_STELEM_I2:
4036 return m_class_get_byval_arg (mono_defaults.int16_class);
4038 case CEE_LDIND_I4:
4039 case CEE_LDIND_U4:
4040 case CEE_STIND_I4:
4041 case CEE_LDELEM_I4:
4042 case CEE_LDELEM_U4:
4043 case CEE_STELEM_I4:
4044 return mono_get_int32_type ();
4046 case CEE_LDIND_I8:
4047 case CEE_STIND_I8:
4048 case CEE_LDELEM_I8:
4049 case CEE_STELEM_I8:
4050 return m_class_get_byval_arg (mono_defaults.int64_class);
4052 case CEE_LDIND_R4:
4053 case CEE_STIND_R4:
4054 case CEE_LDELEM_R4:
4055 case CEE_STELEM_R4:
4056 return m_class_get_byval_arg (mono_defaults.single_class);
4058 case CEE_LDIND_R8:
4059 case CEE_STIND_R8:
4060 case CEE_LDELEM_R8:
4061 case CEE_STELEM_R8:
4062 return m_class_get_byval_arg (mono_defaults.double_class);
4064 case CEE_LDIND_I:
4065 case CEE_STIND_I:
4066 case CEE_LDELEM_I:
4067 case CEE_STELEM_I:
4068 return mono_get_int_type ();
4070 case CEE_LDIND_REF:
4071 case CEE_STIND_REF:
4072 case CEE_LDELEM_REF:
4073 case CEE_STELEM_REF:
4074 return mono_get_object_type ();
4076 default:
4077 g_error ("unknown opcode %02x in mono_type_from_opcode ", opcode);
4078 return NULL;
4082 static void
4083 do_load_indirect (VerifyContext *ctx, int opcode)
4085 ILStackDesc *value;
4086 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
4088 if (!check_underflow (ctx, 1))
4089 return;
4091 value = stack_pop (ctx);
4092 if (!stack_slot_is_managed_pointer (value)) {
4093 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Load indirect not using a manager pointer at 0x%04x", ctx->ip_offset));
4094 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
4095 return;
4098 if (opcode == CEE_LDIND_REF) {
4099 if (stack_slot_get_underlying_type (value) != TYPE_COMPLEX || m_class_is_valuetype (mono_class_from_mono_type_internal (value->type)))
4100 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind_ref expected object byref operation at 0x%04x", ctx->ip_offset));
4101 set_stack_value (ctx, stack_push (ctx), mono_type_get_type_byval (value->type), FALSE);
4102 } else {
4103 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (value->type), TRUE))
4104 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4105 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
4109 static void
4110 do_store_indirect (VerifyContext *ctx, int opcode)
4112 ILStackDesc *addr, *val;
4113 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
4115 if (!check_underflow (ctx, 2))
4116 return;
4118 val = stack_pop (ctx);
4119 addr = stack_pop (ctx);
4121 check_unmanaged_pointer (ctx, addr);
4123 if (!stack_slot_is_managed_pointer (addr) && stack_slot_get_type (addr) != TYPE_PTR) {
4124 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid non-pointer argument to stind at 0x%04x", ctx->ip_offset));
4125 return;
4128 if (stack_slot_is_managed_mutability_pointer (addr)) {
4129 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stind at 0x%04x", ctx->ip_offset));
4130 return;
4133 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (addr->type), TRUE))
4134 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid addr type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4136 if (!verify_stack_type_compatibility (ctx, mono_type_from_opcode (opcode), val))
4137 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4140 static void
4141 do_newarr (VerifyContext *ctx, int token)
4143 ILStackDesc *value;
4144 MonoType *type = get_boxable_mono_type (ctx, token, "newarr");
4146 if (!type)
4147 return;
4149 if (!check_underflow (ctx, 1))
4150 return;
4152 value = stack_pop (ctx);
4153 if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
4154 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));
4156 set_stack_value (ctx, stack_push (ctx), m_class_get_byval_arg (mono_class_create_array (mono_class_from_mono_type_internal (type), 1)), FALSE);
4159 /*FIXME handle arrays that are not 0-indexed*/
4160 static void
4161 do_ldlen (VerifyContext *ctx)
4163 ILStackDesc *value;
4165 if (!check_underflow (ctx, 1))
4166 return;
4168 value = stack_pop (ctx);
4170 if (stack_slot_get_type (value) != TYPE_COMPLEX || value->type->type != MONO_TYPE_SZARRAY)
4171 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type for ldlen at 0x%04x", ctx->ip_offset));
4173 stack_push_val (ctx, TYPE_NATIVE_INT, mono_get_int_type ());
4176 /*FIXME handle arrays that are not 0-indexed*/
4177 /*FIXME handle readonly prefix and CMMP*/
4178 static void
4179 do_ldelema (VerifyContext *ctx, int klass_token)
4181 ILStackDesc *index, *array, *res;
4182 MonoType *type = get_boxable_mono_type (ctx, klass_token, "ldelema");
4183 gboolean valid;
4185 if (!type)
4186 return;
4188 if (!check_underflow (ctx, 2))
4189 return;
4191 index = stack_pop (ctx);
4192 array = stack_pop (ctx);
4194 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4195 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Index type(%s) for ldelema is not an int or a native int at 0x%04x", stack_slot_get_name (index), ctx->ip_offset));
4197 if (!stack_slot_is_null_literal (array)) {
4198 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
4199 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type(%s) for ldelema at 0x%04x", stack_slot_get_name (array), ctx->ip_offset));
4200 else {
4201 if (get_stack_type (type) == TYPE_I4 || get_stack_type (type) == TYPE_NATIVE_INT) {
4202 valid = verify_type_compatibility_full (ctx, type, m_class_get_byval_arg (array->type->data.klass), TRUE);
4203 } else {
4204 valid = mono_metadata_type_equal (type, m_class_get_byval_arg (array->type->data.klass));
4206 if (!valid)
4207 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelema at 0x%04x", ctx->ip_offset));
4211 res = stack_push (ctx);
4212 set_stack_value (ctx, res, type, TRUE);
4213 if (ctx->prefix_set & PREFIX_READONLY) {
4214 ctx->prefix_set &= ~PREFIX_READONLY;
4215 res->stype |= CMMP_MASK;
4218 res->stype |= SAFE_BYREF_MASK;
4222 * FIXME handle arrays that are not 0-indexed
4223 * FIXME handle readonly prefix and CMMP
4225 static void
4226 do_ldelem (VerifyContext *ctx, int opcode, int token)
4228 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
4229 ILStackDesc *index, *array;
4230 MonoType *type;
4231 if (!check_underflow (ctx, 2))
4232 return;
4234 if (opcode == CEE_LDELEM) {
4235 if (!(type = verifier_load_type (ctx, token, "ldelem.any"))) {
4236 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
4237 return;
4239 } else {
4240 type = mono_type_from_opcode (opcode);
4243 index = stack_pop (ctx);
4244 array = stack_pop (ctx);
4246 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4247 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));
4249 if (!stack_slot_is_null_literal (array)) {
4250 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
4251 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));
4252 else {
4253 if (opcode == CEE_LDELEM_REF) {
4254 if (m_class_is_valuetype (array->type->data.klass))
4255 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for ldelem.ref 0x%04x", ctx->ip_offset));
4256 type = m_class_get_byval_arg (array->type->data.klass);
4257 } else {
4258 MonoType *candidate = m_class_get_byval_arg (array->type->data.klass);
4259 if (IS_STRICT_MODE (ctx)) {
4260 MonoType *underlying_type = mono_type_get_underlying_type_any (type);
4261 MonoType *underlying_candidate = mono_type_get_underlying_type_any (candidate);
4262 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)) ||
4263 (IS_ONE_OF2 (underlying_candidate->type, MONO_TYPE_I4, MONO_TYPE_U4) && IS_ONE_OF2 (underlying_type->type, MONO_TYPE_I, MONO_TYPE_U)))
4264 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
4266 if (!verify_type_compatibility_full (ctx, type, candidate, TRUE))
4267 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
4272 set_stack_value (ctx, stack_push (ctx), type, FALSE);
4273 #undef IS_ONE_OF2
4277 * FIXME handle arrays that are not 0-indexed
4279 static void
4280 do_stelem (VerifyContext *ctx, int opcode, int token)
4282 ILStackDesc *index, *array, *value;
4283 MonoType *type;
4284 if (!check_underflow (ctx, 3))
4285 return;
4287 if (opcode == CEE_STELEM) {
4288 if (!(type = verifier_load_type (ctx, token, "stelem.any"))) {
4289 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
4290 return;
4292 } else {
4293 type = mono_type_from_opcode (opcode);
4296 value = stack_pop (ctx);
4297 index = stack_pop (ctx);
4298 array = stack_pop (ctx);
4300 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4301 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));
4303 if (!stack_slot_is_null_literal (array)) {
4304 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY) {
4305 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));
4306 } else {
4307 if (opcode == CEE_STELEM_REF) {
4308 if (m_class_is_valuetype (array->type->data.klass))
4309 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4310 } else if (!verify_type_compatibility_full (ctx, m_class_get_byval_arg (array->type->data.klass), type, TRUE)) {
4311 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4315 if (opcode == CEE_STELEM_REF) {
4316 if (!stack_slot_is_boxed_value (value) && m_class_is_valuetype (mono_class_from_mono_type_internal (value->type)))
4317 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4318 } else if (opcode != CEE_STELEM_REF) {
4319 if (!verify_stack_type_compatibility (ctx, type, value))
4320 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4322 if (stack_slot_is_boxed_value (value) && !MONO_TYPE_IS_REFERENCE (value->type) && !MONO_TYPE_IS_REFERENCE (type))
4323 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));
4328 static void
4329 do_throw (VerifyContext *ctx)
4331 ILStackDesc *exception;
4332 if (!check_underflow (ctx, 1))
4333 return;
4334 exception = stack_pop (ctx);
4336 if (!stack_slot_is_null_literal (exception) && !(stack_slot_get_type (exception) == TYPE_COMPLEX && !m_class_is_valuetype (mono_class_from_mono_type_internal (exception->type))))
4337 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type on stack for throw, expected reference type at 0x%04x", ctx->ip_offset));
4339 if (mono_type_is_generic_argument (exception->type) && !stack_slot_is_boxed_value (exception)) {
4340 char *name = mono_type_full_name (exception->type);
4341 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));
4342 g_free (name);
4344 /*The stack is left empty after a throw*/
4345 ctx->eval.size = 0;
4349 static void
4350 do_endfilter (VerifyContext *ctx)
4352 MonoExceptionClause *clause;
4354 if (IS_STRICT_MODE (ctx)) {
4355 if (ctx->eval.size != 1)
4356 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack size must have one item for endfilter at 0x%04x", ctx->ip_offset));
4358 if (ctx->eval.size >= 1 && stack_slot_get_type (stack_pop (ctx)) != TYPE_I4)
4359 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack item type is not an int32 for endfilter at 0x%04x", ctx->ip_offset));
4362 if ((clause = is_correct_endfilter (ctx, ctx->ip_offset))) {
4363 if (IS_STRICT_MODE (ctx)) {
4364 if (ctx->ip_offset != clause->handler_offset - 2)
4365 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
4366 } else {
4367 if ((ctx->ip_offset != clause->handler_offset - 2) && !MONO_OFFSET_IN_HANDLER (clause, ctx->ip_offset))
4368 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
4370 } else {
4371 if (IS_STRICT_MODE (ctx) && !is_unverifiable_endfilter (ctx, ctx->ip_offset))
4372 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4373 else
4374 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4377 ctx->eval.size = 0;
4380 static void
4381 do_leave (VerifyContext *ctx, int delta)
4383 int target = ((gint32)ctx->ip_offset) + delta;
4384 if (target >= ctx->code_size || target < 0)
4385 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
4387 if (!is_correct_leave (ctx->header, ctx->ip_offset, target))
4388 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ctx->ip_offset));
4389 ctx->eval.size = 0;
4390 ctx->target = target;
4394 * do_static_branch:
4396 * Verify br and br.s opcodes.
4398 static void
4399 do_static_branch (VerifyContext *ctx, int delta)
4401 int target = ctx->ip_offset + delta;
4402 if (target < 0 || target >= ctx->code_size) {
4403 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("branch target out of code at 0x%04x", ctx->ip_offset));
4404 return;
4407 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4408 case 1:
4409 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4410 break;
4411 case 2:
4412 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4413 break;
4416 ctx->target = target;
4419 static void
4420 do_switch (VerifyContext *ctx, int count, const unsigned char *data)
4422 int i, base = ctx->ip_offset + 5 + count * 4;
4423 ILStackDesc *value;
4425 if (!check_underflow (ctx, 1))
4426 return;
4428 value = stack_pop (ctx);
4430 if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
4431 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to switch at 0x%04x", ctx->ip_offset));
4433 for (i = 0; i < count; ++i) {
4434 int target = base + read32 (data + i * 4);
4436 if (target < 0 || target >= ctx->code_size) {
4437 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x out of code at 0x%04x", i, ctx->ip_offset));
4438 return;
4441 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4442 case 1:
4443 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4444 break;
4445 case 2:
4446 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4447 return;
4449 merge_stacks (ctx, &ctx->eval, &ctx->code [target], FALSE, TRUE);
4453 static void
4454 do_load_function_ptr (VerifyContext *ctx, guint32 token, gboolean virtual_)
4456 ILStackDesc *top;
4457 MonoMethod *method;
4459 if (virtual_ && !check_underflow (ctx, 1))
4460 return;
4462 if (!virtual_ && !check_overflow (ctx))
4463 return;
4465 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
4466 method = (MonoMethod *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
4467 if (!method) {
4468 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4469 return;
4471 } else {
4472 if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
4473 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4474 return;
4477 if (!(method = verifier_load_method (ctx, token, virtual_ ? "ldvirtfrn" : "ldftn")))
4478 return;
4481 if (mono_method_is_constructor (method))
4482 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldftn with a constructor at 0x%04x", ctx->ip_offset));
4484 if (virtual_) {
4485 ILStackDesc *top = stack_pop (ctx);
4487 if (stack_slot_get_type (top) != TYPE_COMPLEX || top->type->type == MONO_TYPE_VALUETYPE)
4488 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to ldvirtftn at 0x%04x", ctx->ip_offset));
4490 if (method->flags & METHOD_ATTRIBUTE_STATIC)
4491 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldvirtftn with a constructor at 0x%04x", ctx->ip_offset));
4493 if (!verify_stack_type_compatibility (ctx, m_class_get_byval_arg (method->klass), top))
4494 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unexpected object for ldvirtftn at 0x%04x", ctx->ip_offset));
4497 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL))
4498 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);
4500 top = stack_push_val(ctx, TYPE_PTR, mono_type_create_fnptr_from_mono_method (ctx, method));
4501 top->method = method;
4504 static void
4505 do_sizeof (VerifyContext *ctx, int token)
4507 MonoType *type;
4509 if (!(type = verifier_load_type (ctx, token, "sizeof")))
4510 return;
4512 if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
4513 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type at 0x%04x", ctx->ip_offset));
4514 return;
4517 if (type->type == MONO_TYPE_VOID) {
4518 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type at 0x%04x", ctx->ip_offset));
4519 return;
4522 if (check_overflow (ctx))
4523 set_stack_value (ctx, stack_push (ctx), m_class_get_byval_arg (mono_defaults.uint32_class), FALSE);
4526 /* Stack top can be of any type, the runtime doesn't care and treat everything as an int. */
4527 static void
4528 do_localloc (VerifyContext *ctx)
4530 if (ctx->eval.size != 1) {
4531 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4532 return;
4535 if (in_any_exception_block (ctx->header, ctx->ip_offset)) {
4536 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4537 return;
4540 /*TODO verify top type*/
4541 /* top = */ stack_pop (ctx);
4543 set_stack_value (ctx, stack_push (ctx), mono_get_int_type (), FALSE);
4544 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Instruction localloc in never verifiable at 0x%04x", ctx->ip_offset));
4547 static void
4548 do_ldstr (VerifyContext *ctx, guint32 token)
4550 ERROR_DECL (error);
4551 if (ctx->method->wrapper_type == MONO_WRAPPER_NONE && !image_is_dynamic (ctx->image)) {
4552 if (mono_metadata_token_code (token) != MONO_TOKEN_STRING) {
4553 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string token %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4554 return;
4557 if (!mono_verifier_verify_string_signature (ctx->image, mono_metadata_token_index (token), error)) {
4558 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string index %x at 0x%04x due to: %s", token, ctx->ip_offset, mono_error_get_message (error)), MONO_EXCEPTION_BAD_IMAGE);
4559 mono_error_cleanup (error);
4560 return;
4564 if (check_overflow (ctx))
4565 stack_push_val (ctx, TYPE_COMPLEX, m_class_get_byval_arg (mono_defaults.string_class));
4568 static void
4569 do_refanyval (VerifyContext *ctx, int token)
4571 ILStackDesc *top;
4572 MonoType *type;
4573 if (!check_underflow (ctx, 1))
4574 return;
4576 if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4577 return;
4579 top = stack_pop (ctx);
4581 if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4582 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));
4584 set_stack_value (ctx, stack_push (ctx), type, TRUE);
4587 static void
4588 do_refanytype (VerifyContext *ctx)
4590 ILStackDesc *top;
4592 if (!check_underflow (ctx, 1))
4593 return;
4595 top = stack_pop (ctx);
4597 if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4598 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));
4600 set_stack_value (ctx, stack_push (ctx), m_class_get_byval_arg (mono_defaults.typehandle_class), FALSE);
4604 static void
4605 do_mkrefany (VerifyContext *ctx, int token)
4607 ILStackDesc *top;
4608 MonoType *type;
4609 if (!check_underflow (ctx, 1))
4610 return;
4612 if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4613 return;
4615 top = stack_pop (ctx);
4617 if (stack_slot_is_managed_mutability_pointer (top))
4618 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with mkrefany at 0x%04x", ctx->ip_offset));
4620 if (!stack_slot_is_managed_pointer (top)) {
4621 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));
4622 }else {
4623 MonoType *stack_type = mono_type_get_type_byval (top->type);
4624 if (MONO_TYPE_IS_REFERENCE (type) && !mono_metadata_type_equal (type, stack_type))
4625 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4627 if (!MONO_TYPE_IS_REFERENCE (type) && !verify_type_compatibility_full (ctx, type, stack_type, TRUE))
4628 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4631 set_stack_value (ctx, stack_push (ctx), m_class_get_byval_arg (mono_defaults.typed_reference_class), FALSE);
4634 static void
4635 do_ckfinite (VerifyContext *ctx)
4637 ILStackDesc *top;
4638 if (!check_underflow (ctx, 1))
4639 return;
4641 top = stack_pop (ctx);
4643 if (stack_slot_get_underlying_type (top) != TYPE_R8)
4644 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));
4645 stack_push_stack_val (ctx, top);
4648 * merge_stacks:
4649 * Merge the stacks and perform compat checks. The merge check if types of @from are mergeable with type of @to
4651 * @from holds new values for a given control path
4652 * @to holds the current values of a given control path
4654 * TODO we can eliminate the from argument as all callers pass &ctx->eval
4656 static void
4657 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external)
4659 ERROR_DECL (error);
4660 int i, j;
4661 stack_init (ctx, to);
4663 if (start) {
4664 if (to->flags == IL_CODE_FLAG_NOT_PROCESSED)
4665 from->size = 0;
4666 else
4667 stack_copy (&ctx->eval, to);
4668 goto end_verify;
4669 } else if (!(to->flags & IL_CODE_STACK_MERGED)) {
4670 stack_copy (to, &ctx->eval);
4671 goto end_verify;
4673 VERIFIER_DEBUG ( printf ("performing stack merge %d x %d\n", from->size, to->size); );
4675 if (from->size != to->size) {
4676 VERIFIER_DEBUG ( printf ("different stack sizes %d x %d at 0x%04x\n", from->size, to->size, ctx->ip_offset); );
4677 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));
4678 goto end_verify;
4681 //FIXME we need to preserve CMMP attributes
4682 //FIXME we must take null literals into consideration.
4683 for (i = 0; i < from->size; ++i) {
4684 ILStackDesc *new_slot = from->stack + i;
4685 ILStackDesc *old_slot = to->stack + i;
4686 MonoType *new_type = mono_type_from_stack_slot (new_slot);
4687 MonoType *old_type = mono_type_from_stack_slot (old_slot);
4688 MonoClass *old_class = mono_class_from_mono_type_internal (old_type);
4689 MonoClass *new_class = mono_class_from_mono_type_internal (new_type);
4690 MonoClass *match_class = NULL;
4692 // check for safe byref before the next steps override new_slot
4693 if (stack_slot_is_safe_byref (old_slot) ^ stack_slot_is_safe_byref (new_slot)) {
4694 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));
4695 goto end_verify;
4698 // S := T then U = S (new value is compatible with current value, keep current)
4699 if (verify_stack_type_compatibility (ctx, old_type, new_slot)) {
4700 copy_stack_value (new_slot, old_slot);
4701 continue;
4704 // T := S then U = T (old value is compatible with current value, use new)
4705 if (verify_stack_type_compatibility (ctx, new_type, old_slot)) {
4706 copy_stack_value (old_slot, new_slot);
4707 continue;
4710 /*Both slots are the same boxed valuetype. Simply copy it.*/
4711 if (stack_slot_is_boxed_value (old_slot) &&
4712 stack_slot_is_boxed_value (new_slot) &&
4713 mono_metadata_type_equal (old_type, new_type)) {
4714 copy_stack_value (new_slot, old_slot);
4715 continue;
4718 if (mono_type_is_generic_argument (old_type) || mono_type_is_generic_argument (new_type)) {
4719 char *old_name = stack_slot_full_name (old_slot);
4720 char *new_name = stack_slot_full_name (new_slot);
4721 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));
4722 g_free (old_name);
4723 g_free (new_name);
4724 goto end_verify;
4727 //both are reference types, use closest common super type
4728 if (!m_class_is_valuetype (mono_class_from_mono_type_internal (old_type))
4729 && !m_class_is_valuetype (mono_class_from_mono_type_internal (new_type))
4730 && !stack_slot_is_managed_pointer (old_slot)
4731 && !stack_slot_is_managed_pointer (new_slot)) {
4733 mono_class_setup_supertypes (old_class);
4734 mono_class_setup_supertypes (new_class);
4736 MonoClass **old_class_supertypes = m_class_get_supertypes (old_class);
4737 MonoClass **new_class_supertypes = m_class_get_supertypes (new_class);
4738 for (j = MIN (m_class_get_idepth (old_class), m_class_get_idepth (new_class)) - 1; j > 0; --j) {
4739 if (mono_metadata_type_equal (m_class_get_byval_arg (old_class_supertypes [j]), m_class_get_byval_arg (new_class_supertypes [j]))) {
4740 match_class = old_class_supertypes [j];
4741 goto match_found;
4745 mono_class_setup_interfaces (old_class, error);
4746 if (!is_ok (error)) {
4747 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));
4748 mono_error_cleanup (error);
4749 goto end_verify;
4751 mono_class_setup_interfaces (new_class, error);
4752 if (!is_ok (error)) {
4753 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));
4754 mono_error_cleanup (error);
4755 goto end_verify;
4758 /* if old class is an interface that new class implements */
4759 if (mono_class_is_interface (old_class)) {
4760 if (verifier_class_is_assignable_from (old_class, new_class)) {
4761 match_class = old_class;
4762 goto match_found;
4764 MonoClass **old_class_interfaces = m_class_get_interfaces (old_class);
4765 guint16 old_class_interface_count = m_class_get_interface_count (old_class);
4766 for (j = 0; j < old_class_interface_count; ++j) {
4767 if (verifier_class_is_assignable_from (old_class_interfaces [j], new_class)) {
4768 match_class = old_class_interfaces [j];
4769 goto match_found;
4774 if (mono_class_is_interface (new_class)) {
4775 if (verifier_class_is_assignable_from (new_class, old_class)) {
4776 match_class = new_class;
4777 goto match_found;
4779 MonoClass **new_class_interfaces = m_class_get_interfaces (new_class);
4780 guint16 new_class_interface_count = m_class_get_interface_count (new_class);
4781 for (j = 0; j < new_class_interface_count; ++j) {
4782 if (verifier_class_is_assignable_from (new_class_interfaces [j], old_class)) {
4783 match_class = new_class_interfaces [j];
4784 goto match_found;
4789 //No decent super type found, use object
4790 match_class = mono_defaults.object_class;
4791 goto match_found;
4792 } 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)) {
4793 match_class = mono_defaults.object_class;
4794 goto match_found;
4798 char *old_name = stack_slot_full_name (old_slot);
4799 char *new_name = stack_slot_full_name (new_slot);
4800 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));
4801 g_free (old_name);
4802 g_free (new_name);
4804 set_stack_value (ctx, old_slot, m_class_get_byval_arg (new_class), stack_slot_is_managed_pointer (old_slot));
4805 goto end_verify;
4807 match_found:
4808 g_assert (match_class);
4809 set_stack_value (ctx, old_slot, m_class_get_byval_arg (match_class), stack_slot_is_managed_pointer (old_slot));
4810 set_stack_value (ctx, new_slot, m_class_get_byval_arg (match_class), stack_slot_is_managed_pointer (old_slot));
4811 continue;
4814 end_verify:
4815 if (external)
4816 to->flags |= IL_CODE_FLAG_WAS_TARGET;
4817 to->flags |= IL_CODE_STACK_MERGED;
4820 #define HANDLER_START(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER ? (clause)->data.filter_offset : clause->handler_offset)
4821 #define IS_CATCH_OR_FILTER(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER || (clause)->flags == MONO_EXCEPTION_CLAUSE_NONE)
4824 * is_clause_in_range :
4826 * Returns TRUE if either the protected block or the handler of @clause is in the @start - @end range.
4828 static gboolean
4829 is_clause_in_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4831 if (clause->try_offset >= start && clause->try_offset < end)
4832 return TRUE;
4833 if (HANDLER_START (clause) >= start && HANDLER_START (clause) < end)
4834 return TRUE;
4835 return FALSE;
4839 * is_clause_inside_range :
4841 * Returns TRUE if @clause lies completely inside the @start - @end range.
4843 static gboolean
4844 is_clause_inside_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4846 if (clause->try_offset < start || (clause->try_offset + clause->try_len) > end)
4847 return FALSE;
4848 if (HANDLER_START (clause) < start || (clause->handler_offset + clause->handler_len) > end)
4849 return FALSE;
4850 return TRUE;
4854 * is_clause_nested :
4856 * Returns TRUE if @nested is nested in @clause.
4858 static gboolean
4859 is_clause_nested (MonoExceptionClause *clause, MonoExceptionClause *nested)
4861 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (nested, clause->data.filter_offset, clause->handler_offset))
4862 return TRUE;
4863 return is_clause_inside_range (nested, clause->try_offset, clause->try_offset + clause->try_len) ||
4864 is_clause_inside_range (nested, clause->handler_offset, clause->handler_offset + clause->handler_len);
4867 /* Test the relationship between 2 exception clauses. Follow P.1 12.4.2.7 of ECMA
4868 * the each pair of exception must have the following properties:
4869 * - one is fully nested on another (the outer must not be a filter clause) (the nested one must come earlier)
4870 * - completely disjoin (none of the 3 regions of each entry overlap with the other 3)
4871 * - mutual protection (protected block is EXACT the same, handlers are disjoin and all handler are catch or all handler are filter)
4873 static void
4874 verify_clause_relationship (VerifyContext *ctx, MonoExceptionClause *clause, MonoExceptionClause *to_test)
4876 /*clause is nested*/
4877 if (to_test->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (clause, to_test->data.filter_offset, to_test->handler_offset)) {
4878 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clause inside filter"));
4879 return;
4882 /*wrong nesting order.*/
4883 if (is_clause_nested (clause, to_test)) {
4884 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Nested exception clause appears after enclosing clause"));
4885 return;
4888 /*mutual protection*/
4889 if (clause->try_offset == to_test->try_offset && clause->try_len == to_test->try_len) {
4890 /*handlers are not disjoint*/
4891 if (is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) {
4892 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception handlers overlap"));
4893 return;
4895 /* handlers are not catch or filter */
4896 if (!IS_CATCH_OR_FILTER (clause) || !IS_CATCH_OR_FILTER (to_test)) {
4897 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses with shared protected block are neither catch or filter"));
4898 return;
4900 /*OK*/
4901 return;
4904 /*not completelly disjoint*/
4905 if ((is_clause_in_range (to_test, clause->try_offset, clause->try_offset + clause->try_len) ||
4906 is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) && !is_clause_nested (to_test, clause))
4907 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses overlap"));
4910 #define code_bounds_check(size) \
4911 if (ADDP_IS_GREATER_OR_OVF (ip, size, end)) {\
4912 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Code overrun starting with 0x%x at 0x%04x", *ip, ctx.ip_offset)); \
4913 break; \
4916 static gboolean
4917 mono_opcode_is_prefix (int op)
4919 switch (op) {
4920 case MONO_CEE_UNALIGNED_:
4921 case MONO_CEE_VOLATILE_:
4922 case MONO_CEE_TAIL_:
4923 case MONO_CEE_CONSTRAINED_:
4924 case MONO_CEE_READONLY_:
4925 return TRUE;
4927 return FALSE;
4931 * FIXME: need to distinguish between valid and verifiable.
4932 * Need to keep track of types on the stack.
4936 * mono_method_verify:
4937 * Verify types for opcodes.
4939 GSList*
4940 mono_method_verify (MonoMethod *method, int level)
4942 ERROR_DECL (error);
4943 const unsigned char *ip, *code_start;
4944 const unsigned char *end;
4945 MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
4947 int i, n, need_merge = 0, start = 0;
4948 guint ip_offset = 0, prefix = 0;
4949 MonoGenericContext *generic_context = NULL;
4950 MonoImage *image;
4951 VerifyContext ctx;
4952 GSList *tmp;
4953 VERIFIER_DEBUG ( printf ("Verify IL for method %s %s %s\n", method->klass->name_space, method->klass->name, method->name); );
4955 init_verifier_stats ();
4957 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
4958 (method->flags & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT))) {
4959 return NULL;
4962 memset (&ctx, 0, sizeof (VerifyContext));
4964 //FIXME use mono_method_get_signature_full
4965 ctx.signature = mono_method_signature_internal (method);
4966 if (!ctx.signature) {
4967 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method signature"));
4969 finish_collect_stats ();
4970 return ctx.list;
4972 if (!method->is_generic && !mono_class_is_gtd (method->klass) && ctx.signature->has_type_parameters) {
4973 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Method and signature don't match in terms of genericity"));
4974 finish_collect_stats ();
4975 return ctx.list;
4978 ctx.header = mono_method_get_header_checked (method, error);
4979 if (!ctx.header) {
4980 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method header due to %s", mono_error_get_message (error)));
4981 mono_error_cleanup (error);
4982 finish_collect_stats ();
4983 return ctx.list;
4985 ctx.method = method;
4986 code_start = ip = ctx.header->code;
4987 end = ip + ctx.header->code_size;
4988 ctx.image = image = m_class_get_image (method->klass);
4991 ctx.max_args = ctx.signature->param_count + ctx.signature->hasthis;
4992 ctx.max_stack = ctx.header->max_stack;
4993 ctx.verifiable = ctx.valid = 1;
4994 ctx.level = level;
4996 ctx.code = g_new (ILCodeDesc, ctx.header->code_size);
4997 ctx.code_size = ctx.header->code_size;
4998 _MEM_ALLOC (sizeof (ILCodeDesc) * ctx.header->code_size);
5000 memset(ctx.code, 0, sizeof (ILCodeDesc) * ctx.header->code_size);
5002 ctx.num_locals = ctx.header->num_locals;
5003 ctx.locals = (MonoType **)g_memdup (ctx.header->locals, sizeof (MonoType*) * ctx.header->num_locals);
5004 _MEM_ALLOC (sizeof (MonoType*) * ctx.header->num_locals);
5005 ctx.locals_verification_state = g_new0 (char, ctx.num_locals);
5007 if (ctx.num_locals > 0 && !ctx.header->init_locals)
5008 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Method with locals variable but without init locals set"));
5010 ctx.params = g_new (MonoType*, ctx.max_args);
5011 _MEM_ALLOC (sizeof (MonoType*) * ctx.max_args);
5013 if (ctx.signature->hasthis)
5014 ctx.params [0] = m_class_is_valuetype (method->klass) ? m_class_get_this_arg (method->klass) : m_class_get_byval_arg (method->klass);
5015 memcpy (ctx.params + ctx.signature->hasthis, ctx.signature->params, sizeof (MonoType *) * ctx.signature->param_count);
5017 if (ctx.signature->is_inflated)
5018 ctx.generic_context = generic_context = mono_method_get_context (method);
5020 if (!generic_context && (mono_class_is_gtd (method->klass) || method->is_generic)) {
5021 if (method->is_generic)
5022 ctx.generic_context = generic_context = &(mono_method_get_generic_container (method)->context);
5023 else
5024 ctx.generic_context = generic_context = &mono_class_get_generic_container (method->klass)->context;
5027 for (i = 0; i < ctx.num_locals; ++i) {
5028 MonoType *uninflated = ctx.locals [i];
5029 ctx.locals [i] = mono_class_inflate_generic_type_checked (ctx.locals [i], ctx.generic_context, error);
5030 if (!is_ok (error)) {
5031 char *name = mono_type_full_name (ctx.locals [i] ? ctx.locals [i] : uninflated);
5032 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %d of type %s", i, name));
5033 g_free (name);
5034 mono_error_cleanup (error);
5035 /* we must not free (in cleanup) what was not yet allocated (but only copied) */
5036 ctx.num_locals = i;
5037 ctx.max_args = 0;
5038 goto cleanup;
5041 for (i = 0; i < ctx.max_args; ++i) {
5042 MonoType *uninflated = ctx.params [i];
5043 ctx.params [i] = mono_class_inflate_generic_type_checked (ctx.params [i], ctx.generic_context, error);
5044 if (!is_ok (error)) {
5045 char *name = mono_type_full_name (ctx.params [i] ? ctx.params [i] : uninflated);
5046 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %d of type %s", i, name));
5047 g_free (name);
5048 mono_error_cleanup (error);
5049 /* we must not free (in cleanup) what was not yet allocated (but only copied) */
5050 ctx.max_args = i;
5051 goto cleanup;
5054 stack_init (&ctx, &ctx.eval);
5056 for (i = 0; i < ctx.num_locals; ++i) {
5057 if (!mono_type_is_valid_in_context (&ctx, ctx.locals [i]))
5058 break;
5059 if (get_stack_type (ctx.locals [i]) == TYPE_INV) {
5060 char *name = mono_type_full_name (ctx.locals [i]);
5061 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %i of type %s", i, name));
5062 g_free (name);
5063 break;
5068 for (i = 0; i < ctx.max_args; ++i) {
5069 if (!mono_type_is_valid_in_context (&ctx, ctx.params [i]))
5070 break;
5072 if (get_stack_type (ctx.params [i]) == TYPE_INV) {
5073 char *name = mono_type_full_name (ctx.params [i]);
5074 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %i of type %s", i, name));
5075 g_free (name);
5076 break;
5080 if (!ctx.valid)
5081 goto cleanup;
5083 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
5084 MonoExceptionClause *clause = ctx.header->clauses + i;
5085 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); );
5087 if (clause->try_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, ctx.code_size))
5088 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause out of bounds at 0x%04x", clause->try_offset));
5090 if (clause->try_len <= 0)
5091 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause len <= 0 at 0x%04x", clause->try_offset));
5093 if (clause->handler_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->handler_offset, clause->handler_len, ctx.code_size))
5094 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause out of bounds at 0x%04x", clause->try_offset));
5096 if (clause->handler_len <= 0)
5097 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause len <= 0 at 0x%04x", clause->try_offset));
5099 if (clause->try_offset < clause->handler_offset && ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, HANDLER_START (clause)))
5100 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try block (at 0x%04x) includes handler block (at 0x%04x)", clause->try_offset, clause->handler_offset));
5102 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5103 if (clause->data.filter_offset > ctx.code_size)
5104 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause out of bounds at 0x%04x", clause->try_offset));
5106 if (clause->data.filter_offset >= clause->handler_offset)
5107 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause must come before the handler clause at 0x%04x", clause->data.filter_offset));
5110 for (n = i + 1; n < ctx.header->num_clauses && ctx.valid; ++n)
5111 verify_clause_relationship (&ctx, clause, ctx.header->clauses + n);
5113 if (!ctx.valid)
5114 break;
5116 ctx.code [clause->try_offset].flags |= IL_CODE_FLAG_WAS_TARGET;
5117 if (clause->try_offset + clause->try_len < ctx.code_size)
5118 ctx.code [clause->try_offset + clause->try_len].flags |= IL_CODE_FLAG_WAS_TARGET;
5119 if (clause->handler_offset + clause->handler_len < ctx.code_size)
5120 ctx.code [clause->handler_offset + clause->handler_len].flags |= IL_CODE_FLAG_WAS_TARGET;
5122 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
5123 if (!clause->data.catch_class) {
5124 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Catch clause %d with invalid type", i));
5125 break;
5127 if (!mono_type_is_valid_in_context (&ctx, m_class_get_byval_arg (clause->data.catch_class)))
5128 break;
5130 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, clause->data.catch_class);
5132 else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5133 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->data.filter_offset, mono_defaults.exception_class);
5134 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, mono_defaults.exception_class);
5138 if (!ctx.valid)
5139 goto cleanup;
5141 original_bb = bb = mono_basic_block_split (method, error, ctx.header);
5142 if (!is_ok (error)) {
5143 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid branch target: %s", mono_error_get_message (error)));
5144 mono_error_cleanup (error);
5145 goto cleanup;
5147 g_assert (bb);
5149 while (ip < end && ctx.valid) {
5150 int op_size;
5151 ip_offset = (guint) (ip - code_start);
5153 const unsigned char *ip_copy = ip;
5154 MonoOpcodeEnum op;
5156 if (ip_offset > bb->end) {
5157 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block at [0x%04x] targets middle instruction at 0x%04x", bb->end, ip_offset));
5158 goto cleanup;
5161 if (ip_offset == bb->end)
5162 bb = bb->next;
5164 op_size = mono_opcode_value_and_size (&ip_copy, end, &op);
5165 if (op_size == -1) {
5166 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ip_offset));
5167 goto cleanup;
5170 if (ADD_IS_GREATER_OR_OVF (ip_offset, op_size, bb->end)) {
5171 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block targets middle of instruction at 0x%04x", ip_offset));
5172 goto cleanup;
5175 /*Last Instruction*/
5176 if (ip_offset + op_size == bb->end && mono_opcode_is_prefix (op)) {
5177 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));
5178 goto cleanup;
5182 ctx.ip_offset = ip_offset = (guint) (ip - code_start);
5184 /*We need to check against fallthrou in and out of protected blocks.
5185 * For fallout we check the once a protected block ends, if the start flag is not set.
5186 * Likewise for fallthru in, we check if ip is the start of a protected block and start is not set
5187 * TODO convert these checks to be done using flags and not this loop
5189 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
5190 MonoExceptionClause *clause = ctx.header->clauses + i;
5192 if ((clause->try_offset + clause->try_len == ip_offset) && start == 0) {
5193 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru off try block at 0x%04x", ip_offset));
5194 start = 1;
5197 if ((clause->handler_offset + clause->handler_len == ip_offset) && start == 0) {
5198 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
5199 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
5200 else
5201 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
5202 start = 1;
5205 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && clause->handler_offset == ip_offset && start == 0) {
5206 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of filter block at 0x%04x", ip_offset));
5207 start = 1;
5210 if (clause->handler_offset == ip_offset && start == 0) {
5211 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru handler block at 0x%04x", ip_offset));
5212 start = 1;
5215 if (clause->try_offset == ip_offset && ctx.eval.size > 0 && start == 0) {
5216 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Try to enter try block with a non-empty stack at 0x%04x", ip_offset));
5217 start = 1;
5221 /*This must be done after fallthru detection otherwise it won't happen.*/
5222 if (bb->dead) {
5223 /*FIXME remove this once we move all bad branch checking code to use BB only*/
5224 ctx.code [ip_offset].flags |= IL_CODE_FLAG_SEEN;
5225 ip += op_size;
5226 continue;
5229 if (!ctx.valid)
5230 break;
5232 if (need_merge) {
5233 VERIFIER_DEBUG ( printf ("extra merge needed! 0x%04x \n", ctx.target); );
5234 merge_stacks (&ctx, &ctx.eval, &ctx.code [ctx.target], FALSE, TRUE);
5235 need_merge = 0;
5237 merge_stacks (&ctx, &ctx.eval, &ctx.code[ip_offset], start, FALSE);
5238 start = 0;
5240 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
5241 #ifdef MONO_VERIFIER_DEBUG
5243 char *discode;
5244 discode = mono_disasm_code_one (NULL, method, ip, NULL);
5245 discode [strlen (discode) - 1] = 0; /* no \n */
5246 g_print ("[%d] %-29s (%d)\n", ip_offset, discode, ctx.eval.size);
5247 g_free (discode);
5249 dump_stack_state (&ctx.code [ip_offset]);
5250 dump_stack_state (&ctx.eval);
5251 #endif
5253 switch (*ip) {
5254 case CEE_NOP:
5255 case CEE_BREAK:
5256 ++ip;
5257 break;
5259 case CEE_LDARG_0:
5260 case CEE_LDARG_1:
5261 case CEE_LDARG_2:
5262 case CEE_LDARG_3:
5263 push_arg (&ctx, *ip - CEE_LDARG_0, FALSE);
5264 ++ip;
5265 break;
5267 case CEE_LDARG_S:
5268 case CEE_LDARGA_S:
5269 code_bounds_check (2);
5270 push_arg (&ctx, ip [1], *ip == CEE_LDARGA_S);
5271 ip += 2;
5272 break;
5274 case CEE_ADD_OVF_UN:
5275 do_binop (&ctx, *ip, add_ovf_un_table);
5276 ++ip;
5277 break;
5279 case CEE_SUB_OVF_UN:
5280 do_binop (&ctx, *ip, sub_ovf_un_table);
5281 ++ip;
5282 break;
5284 case CEE_ADD_OVF:
5285 case CEE_SUB_OVF:
5286 case CEE_MUL_OVF:
5287 case CEE_MUL_OVF_UN:
5288 do_binop (&ctx, *ip, bin_ovf_table);
5289 ++ip;
5290 break;
5292 case CEE_ADD:
5293 do_binop (&ctx, *ip, add_table);
5294 ++ip;
5295 break;
5297 case CEE_SUB:
5298 do_binop (&ctx, *ip, sub_table);
5299 ++ip;
5300 break;
5302 case CEE_MUL:
5303 case CEE_DIV:
5304 case CEE_REM:
5305 do_binop (&ctx, *ip, bin_op_table);
5306 ++ip;
5307 break;
5309 case CEE_AND:
5310 case CEE_DIV_UN:
5311 case CEE_OR:
5312 case CEE_REM_UN:
5313 case CEE_XOR:
5314 do_binop (&ctx, *ip, int_bin_op_table);
5315 ++ip;
5316 break;
5318 case CEE_SHL:
5319 case CEE_SHR:
5320 case CEE_SHR_UN:
5321 do_binop (&ctx, *ip, shift_op_table);
5322 ++ip;
5323 break;
5325 case CEE_POP:
5326 if (!check_underflow (&ctx, 1))
5327 break;
5328 stack_pop_safe (&ctx);
5329 ++ip;
5330 break;
5332 case CEE_RET:
5333 do_ret (&ctx);
5334 ++ip;
5335 start = 1;
5336 break;
5338 case CEE_LDLOC_0:
5339 case CEE_LDLOC_1:
5340 case CEE_LDLOC_2:
5341 case CEE_LDLOC_3:
5342 /*TODO support definite assignment verification? */
5343 push_local (&ctx, *ip - CEE_LDLOC_0, FALSE);
5344 ++ip;
5345 break;
5347 case CEE_STLOC_0:
5348 case CEE_STLOC_1:
5349 case CEE_STLOC_2:
5350 case CEE_STLOC_3:
5351 store_local (&ctx, *ip - CEE_STLOC_0);
5352 ++ip;
5353 break;
5355 case CEE_STLOC_S:
5356 code_bounds_check (2);
5357 store_local (&ctx, ip [1]);
5358 ip += 2;
5359 break;
5361 case CEE_STARG_S:
5362 code_bounds_check (2);
5363 store_arg (&ctx, ip [1]);
5364 ip += 2;
5365 break;
5367 case CEE_LDC_I4_M1:
5368 case CEE_LDC_I4_0:
5369 case CEE_LDC_I4_1:
5370 case CEE_LDC_I4_2:
5371 case CEE_LDC_I4_3:
5372 case CEE_LDC_I4_4:
5373 case CEE_LDC_I4_5:
5374 case CEE_LDC_I4_6:
5375 case CEE_LDC_I4_7:
5376 case CEE_LDC_I4_8:
5377 if (check_overflow (&ctx))
5378 stack_push_val (&ctx, TYPE_I4, mono_get_int32_type ());
5379 ++ip;
5380 break;
5382 case CEE_LDC_I4_S:
5383 code_bounds_check (2);
5384 if (check_overflow (&ctx))
5385 stack_push_val (&ctx, TYPE_I4, mono_get_int32_type ());
5386 ip += 2;
5387 break;
5389 case CEE_LDC_I4:
5390 code_bounds_check (5);
5391 if (check_overflow (&ctx))
5392 stack_push_val (&ctx,TYPE_I4, mono_get_int32_type ());
5393 ip += 5;
5394 break;
5396 case CEE_LDC_I8:
5397 code_bounds_check (9);
5398 if (check_overflow (&ctx))
5399 stack_push_val (&ctx,TYPE_I8, m_class_get_byval_arg (mono_defaults.int64_class));
5400 ip += 9;
5401 break;
5403 case CEE_LDC_R4:
5404 code_bounds_check (5);
5405 if (check_overflow (&ctx))
5406 stack_push_val (&ctx, TYPE_R8, m_class_get_byval_arg (mono_defaults.double_class));
5407 ip += 5;
5408 break;
5410 case CEE_LDC_R8:
5411 code_bounds_check (9);
5412 if (check_overflow (&ctx))
5413 stack_push_val (&ctx, TYPE_R8, m_class_get_byval_arg (mono_defaults.double_class));
5414 ip += 9;
5415 break;
5417 case CEE_LDNULL:
5418 if (check_overflow (&ctx))
5419 stack_push_val (&ctx, TYPE_COMPLEX | NULL_LITERAL_MASK, mono_get_object_type ());
5420 ++ip;
5421 break;
5423 case CEE_BEQ_S:
5424 case CEE_BNE_UN_S:
5425 code_bounds_check (2);
5426 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_eq_op);
5427 ip += 2;
5428 need_merge = 1;
5429 break;
5431 case CEE_BGE_S:
5432 case CEE_BGT_S:
5433 case CEE_BLE_S:
5434 case CEE_BLT_S:
5435 case CEE_BGE_UN_S:
5436 case CEE_BGT_UN_S:
5437 case CEE_BLE_UN_S:
5438 case CEE_BLT_UN_S:
5439 code_bounds_check (2);
5440 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_op);
5441 ip += 2;
5442 need_merge = 1;
5443 break;
5445 case CEE_BEQ:
5446 case CEE_BNE_UN:
5447 code_bounds_check (5);
5448 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_eq_op);
5449 ip += 5;
5450 need_merge = 1;
5451 break;
5453 case CEE_BGE:
5454 case CEE_BGT:
5455 case CEE_BLE:
5456 case CEE_BLT:
5457 case CEE_BGE_UN:
5458 case CEE_BGT_UN:
5459 case CEE_BLE_UN:
5460 case CEE_BLT_UN:
5461 code_bounds_check (5);
5462 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_op);
5463 ip += 5;
5464 need_merge = 1;
5465 break;
5467 case CEE_LDLOC_S:
5468 case CEE_LDLOCA_S:
5469 code_bounds_check (2);
5470 push_local (&ctx, ip[1], *ip == CEE_LDLOCA_S);
5471 ip += 2;
5472 break;
5474 case CEE_UNUSED99:
5475 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5476 ++ip;
5477 break;
5479 case CEE_DUP: {
5480 ILStackDesc *top;
5481 if (!check_underflow (&ctx, 1))
5482 break;
5483 if (!check_overflow (&ctx))
5484 break;
5485 top = stack_push (&ctx);
5486 copy_stack_value (top, stack_peek (&ctx, 1));
5487 ++ip;
5488 break;
5491 case CEE_JMP:
5492 code_bounds_check (5);
5493 if (ctx.eval.size)
5494 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Eval stack must be empty in jmp at 0x%04x", ip_offset));
5495 /* token = read32 (ip + 1); */
5496 if (in_any_block (ctx.header, ip_offset))
5497 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("jmp cannot escape exception blocks at 0x%04x", ip_offset));
5499 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction jmp is not verifiable at 0x%04x", ctx.ip_offset));
5501 * FIXME: check signature, retval, arguments etc.
5503 ip += 5;
5504 break;
5505 case CEE_CALL:
5506 case CEE_CALLVIRT:
5507 code_bounds_check (5);
5508 do_invoke_method (&ctx, read32 (ip + 1), *ip == CEE_CALLVIRT);
5509 ip += 5;
5510 break;
5512 case CEE_CALLI:
5513 code_bounds_check (5);
5514 /* token = read32 (ip + 1); */
5516 * FIXME: check signature, retval, arguments etc.
5517 * FIXME: check requirements for tail call
5519 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction calli is not verifiable at 0x%04x", ctx.ip_offset));
5520 ip += 5;
5521 break;
5522 case CEE_BR_S:
5523 code_bounds_check (2);
5524 do_static_branch (&ctx, (signed char)ip [1] + 2);
5525 need_merge = 1;
5526 ip += 2;
5527 start = 1;
5528 break;
5530 case CEE_BRFALSE_S:
5531 case CEE_BRTRUE_S:
5532 code_bounds_check (2);
5533 do_boolean_branch_op (&ctx, (signed char)ip [1] + 2);
5534 ip += 2;
5535 need_merge = 1;
5536 break;
5538 case CEE_BR:
5539 code_bounds_check (5);
5540 do_static_branch (&ctx, (gint32)read32 (ip + 1) + 5);
5541 need_merge = 1;
5542 ip += 5;
5543 start = 1;
5544 break;
5546 case CEE_BRFALSE:
5547 case CEE_BRTRUE:
5548 code_bounds_check (5);
5549 do_boolean_branch_op (&ctx, (gint32)read32 (ip + 1) + 5);
5550 ip += 5;
5551 need_merge = 1;
5552 break;
5554 case CEE_SWITCH: {
5555 guint32 entries;
5556 code_bounds_check (5);
5557 entries = read32 (ip + 1);
5559 if (entries > 0xFFFFFFFFU / sizeof (guint32))
5560 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Too many switch entries %x at 0x%04x", entries, ctx.ip_offset));
5562 ip += 5;
5563 code_bounds_check (sizeof (guint32) * entries);
5565 do_switch (&ctx, entries, ip);
5566 ip += sizeof (guint32) * entries;
5567 break;
5569 case CEE_LDIND_I1:
5570 case CEE_LDIND_U1:
5571 case CEE_LDIND_I2:
5572 case CEE_LDIND_U2:
5573 case CEE_LDIND_I4:
5574 case CEE_LDIND_U4:
5575 case CEE_LDIND_I8:
5576 case CEE_LDIND_I:
5577 case CEE_LDIND_R4:
5578 case CEE_LDIND_R8:
5579 case CEE_LDIND_REF:
5580 do_load_indirect (&ctx, *ip);
5581 ++ip;
5582 break;
5584 case CEE_STIND_REF:
5585 case CEE_STIND_I1:
5586 case CEE_STIND_I2:
5587 case CEE_STIND_I4:
5588 case CEE_STIND_I8:
5589 case CEE_STIND_R4:
5590 case CEE_STIND_R8:
5591 case CEE_STIND_I:
5592 do_store_indirect (&ctx, *ip);
5593 ++ip;
5594 break;
5596 case CEE_NOT:
5597 case CEE_NEG:
5598 do_unary_math_op (&ctx, *ip);
5599 ++ip;
5600 break;
5602 case CEE_CONV_I1:
5603 case CEE_CONV_I2:
5604 case CEE_CONV_I4:
5605 case CEE_CONV_U1:
5606 case CEE_CONV_U2:
5607 case CEE_CONV_U4:
5608 do_conversion (&ctx, TYPE_I4);
5609 ++ip;
5610 break;
5612 case CEE_CONV_I8:
5613 case CEE_CONV_U8:
5614 do_conversion (&ctx, TYPE_I8);
5615 ++ip;
5616 break;
5618 case CEE_CONV_R4:
5619 case CEE_CONV_R8:
5620 case CEE_CONV_R_UN:
5621 do_conversion (&ctx, TYPE_R8);
5622 ++ip;
5623 break;
5625 case CEE_CONV_I:
5626 case CEE_CONV_U:
5627 do_conversion (&ctx, TYPE_NATIVE_INT);
5628 ++ip;
5629 break;
5631 case CEE_CPOBJ:
5632 code_bounds_check (5);
5633 do_cpobj (&ctx, read32 (ip + 1));
5634 ip += 5;
5635 break;
5637 case CEE_LDOBJ:
5638 code_bounds_check (5);
5639 do_ldobj_value (&ctx, read32 (ip + 1));
5640 ip += 5;
5641 break;
5643 case CEE_LDSTR:
5644 code_bounds_check (5);
5645 do_ldstr (&ctx, read32 (ip + 1));
5646 ip += 5;
5647 break;
5649 case CEE_NEWOBJ:
5650 code_bounds_check (5);
5651 do_newobj (&ctx, read32 (ip + 1));
5652 ip += 5;
5653 break;
5655 case CEE_CASTCLASS:
5656 case CEE_ISINST:
5657 code_bounds_check (5);
5658 do_cast (&ctx, read32 (ip + 1), *ip == CEE_CASTCLASS ? "castclass" : "isinst");
5659 ip += 5;
5660 break;
5662 case CEE_UNUSED58:
5663 case CEE_UNUSED1:
5664 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5665 ++ip;
5666 break;
5668 case CEE_UNBOX:
5669 code_bounds_check (5);
5670 do_unbox_value (&ctx, read32 (ip + 1));
5671 ip += 5;
5672 break;
5674 case CEE_THROW:
5675 do_throw (&ctx);
5676 start = 1;
5677 ++ip;
5678 break;
5680 case CEE_LDFLD:
5681 case CEE_LDFLDA:
5682 code_bounds_check (5);
5683 do_push_field (&ctx, read32 (ip + 1), *ip == CEE_LDFLDA);
5684 ip += 5;
5685 break;
5687 case CEE_LDSFLD:
5688 case CEE_LDSFLDA:
5689 code_bounds_check (5);
5690 do_push_static_field (&ctx, read32 (ip + 1), *ip == CEE_LDSFLDA);
5691 ip += 5;
5692 break;
5694 case CEE_STFLD:
5695 code_bounds_check (5);
5696 do_store_field (&ctx, read32 (ip + 1));
5697 ip += 5;
5698 break;
5700 case CEE_STSFLD:
5701 code_bounds_check (5);
5702 do_store_static_field (&ctx, read32 (ip + 1));
5703 ip += 5;
5704 break;
5706 case CEE_STOBJ:
5707 code_bounds_check (5);
5708 do_stobj (&ctx, read32 (ip + 1));
5709 ip += 5;
5710 break;
5712 case CEE_CONV_OVF_I1_UN:
5713 case CEE_CONV_OVF_I2_UN:
5714 case CEE_CONV_OVF_I4_UN:
5715 case CEE_CONV_OVF_U1_UN:
5716 case CEE_CONV_OVF_U2_UN:
5717 case CEE_CONV_OVF_U4_UN:
5718 do_conversion (&ctx, TYPE_I4);
5719 ++ip;
5720 break;
5722 case CEE_CONV_OVF_I8_UN:
5723 case CEE_CONV_OVF_U8_UN:
5724 do_conversion (&ctx, TYPE_I8);
5725 ++ip;
5726 break;
5728 case CEE_CONV_OVF_I_UN:
5729 case CEE_CONV_OVF_U_UN:
5730 do_conversion (&ctx, TYPE_NATIVE_INT);
5731 ++ip;
5732 break;
5734 case CEE_BOX:
5735 code_bounds_check (5);
5736 do_box_value (&ctx, read32 (ip + 1));
5737 ip += 5;
5738 break;
5740 case CEE_NEWARR:
5741 code_bounds_check (5);
5742 do_newarr (&ctx, read32 (ip + 1));
5743 ip += 5;
5744 break;
5746 case CEE_LDLEN:
5747 do_ldlen (&ctx);
5748 ++ip;
5749 break;
5751 case CEE_LDELEMA:
5752 code_bounds_check (5);
5753 do_ldelema (&ctx, read32 (ip + 1));
5754 ip += 5;
5755 break;
5757 case CEE_LDELEM_I1:
5758 case CEE_LDELEM_U1:
5759 case CEE_LDELEM_I2:
5760 case CEE_LDELEM_U2:
5761 case CEE_LDELEM_I4:
5762 case CEE_LDELEM_U4:
5763 case CEE_LDELEM_I8:
5764 case CEE_LDELEM_I:
5765 case CEE_LDELEM_R4:
5766 case CEE_LDELEM_R8:
5767 case CEE_LDELEM_REF:
5768 do_ldelem (&ctx, *ip, 0);
5769 ++ip;
5770 break;
5772 case CEE_STELEM_I:
5773 case CEE_STELEM_I1:
5774 case CEE_STELEM_I2:
5775 case CEE_STELEM_I4:
5776 case CEE_STELEM_I8:
5777 case CEE_STELEM_R4:
5778 case CEE_STELEM_R8:
5779 case CEE_STELEM_REF:
5780 do_stelem (&ctx, *ip, 0);
5781 ++ip;
5782 break;
5784 case CEE_LDELEM:
5785 code_bounds_check (5);
5786 do_ldelem (&ctx, *ip, read32 (ip + 1));
5787 ip += 5;
5788 break;
5790 case CEE_STELEM:
5791 code_bounds_check (5);
5792 do_stelem (&ctx, *ip, read32 (ip + 1));
5793 ip += 5;
5794 break;
5796 case CEE_UNBOX_ANY:
5797 code_bounds_check (5);
5798 do_unbox_any (&ctx, read32 (ip + 1));
5799 ip += 5;
5800 break;
5802 case CEE_CONV_OVF_I1:
5803 case CEE_CONV_OVF_U1:
5804 case CEE_CONV_OVF_I2:
5805 case CEE_CONV_OVF_U2:
5806 case CEE_CONV_OVF_I4:
5807 case CEE_CONV_OVF_U4:
5808 do_conversion (&ctx, TYPE_I4);
5809 ++ip;
5810 break;
5812 case CEE_CONV_OVF_I8:
5813 case CEE_CONV_OVF_U8:
5814 do_conversion (&ctx, TYPE_I8);
5815 ++ip;
5816 break;
5818 case CEE_CONV_OVF_I:
5819 case CEE_CONV_OVF_U:
5820 do_conversion (&ctx, TYPE_NATIVE_INT);
5821 ++ip;
5822 break;
5824 case CEE_REFANYVAL:
5825 code_bounds_check (5);
5826 do_refanyval (&ctx, read32 (ip + 1));
5827 ip += 5;
5828 break;
5830 case CEE_CKFINITE:
5831 do_ckfinite (&ctx);
5832 ++ip;
5833 break;
5835 case CEE_MKREFANY:
5836 code_bounds_check (5);
5837 do_mkrefany (&ctx, read32 (ip + 1));
5838 ip += 5;
5839 break;
5841 case CEE_LDTOKEN:
5842 code_bounds_check (5);
5843 do_load_token (&ctx, read32 (ip + 1));
5844 ip += 5;
5845 break;
5847 case CEE_ENDFINALLY:
5848 if (!is_correct_endfinally (ctx.header, ip_offset))
5849 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("endfinally must be used inside a finally/fault handler at 0x%04x", ctx.ip_offset));
5850 ctx.eval.size = 0;
5851 start = 1;
5852 ++ip;
5853 break;
5855 case CEE_LEAVE:
5856 code_bounds_check (5);
5857 do_leave (&ctx, read32 (ip + 1) + 5);
5858 ip += 5;
5859 start = 1;
5860 need_merge = 1;
5861 break;
5863 case CEE_LEAVE_S:
5864 code_bounds_check (2);
5865 do_leave (&ctx, (signed char)ip [1] + 2);
5866 ip += 2;
5867 start = 1;
5868 need_merge = 1;
5869 break;
5871 case CEE_PREFIX1:
5872 code_bounds_check (2);
5873 ++ip;
5874 switch (*ip) {
5875 case CEE_STLOC:
5876 code_bounds_check (3);
5877 store_local (&ctx, read16 (ip + 1));
5878 ip += 3;
5879 break;
5881 case CEE_CEQ:
5882 do_cmp_op (&ctx, cmp_br_eq_op, *ip);
5883 ++ip;
5884 break;
5886 case CEE_CGT:
5887 case CEE_CGT_UN:
5888 case CEE_CLT:
5889 case CEE_CLT_UN:
5890 do_cmp_op (&ctx, cmp_br_op, *ip);
5891 ++ip;
5892 break;
5894 case CEE_STARG:
5895 code_bounds_check (3);
5896 store_arg (&ctx, read16 (ip + 1) );
5897 ip += 3;
5898 break;
5901 case CEE_ARGLIST:
5902 if (!check_overflow (&ctx))
5903 break;
5904 if (ctx.signature->call_convention != MONO_CALL_VARARG)
5905 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot use arglist on method without VARGARG calling convention at 0x%04x", ctx.ip_offset));
5906 set_stack_value (&ctx, stack_push (&ctx), m_class_get_byval_arg (mono_defaults.argumenthandle_class), FALSE);
5907 ++ip;
5908 break;
5910 case CEE_LDFTN:
5911 code_bounds_check (5);
5912 do_load_function_ptr (&ctx, read32 (ip + 1), FALSE);
5913 ip += 5;
5914 break;
5916 case CEE_LDVIRTFTN:
5917 code_bounds_check (5);
5918 do_load_function_ptr (&ctx, read32 (ip + 1), TRUE);
5919 ip += 5;
5920 break;
5922 case CEE_LDARG:
5923 case CEE_LDARGA:
5924 code_bounds_check (3);
5925 push_arg (&ctx, read16 (ip + 1), *ip == CEE_LDARGA);
5926 ip += 3;
5927 break;
5929 case CEE_LDLOC:
5930 case CEE_LDLOCA:
5931 code_bounds_check (3);
5932 push_local (&ctx, read16 (ip + 1), *ip == CEE_LDLOCA);
5933 ip += 3;
5934 break;
5936 case CEE_LOCALLOC:
5937 do_localloc (&ctx);
5938 ++ip;
5939 break;
5941 case CEE_UNUSED56:
5942 case CEE_UNUSED57:
5943 case CEE_UNUSED70:
5944 case CEE_UNUSED:
5945 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5946 ++ip;
5947 break;
5948 case CEE_ENDFILTER:
5949 do_endfilter (&ctx);
5950 start = 1;
5951 ++ip;
5952 break;
5953 case CEE_UNALIGNED_:
5954 code_bounds_check (2);
5955 prefix |= PREFIX_UNALIGNED;
5956 ip += 2;
5957 break;
5958 case CEE_VOLATILE_:
5959 prefix |= PREFIX_VOLATILE;
5960 ++ip;
5961 break;
5962 case CEE_TAIL_:
5963 prefix |= PREFIX_TAIL;
5964 ++ip;
5965 if (ip < end && (*ip != CEE_CALL && *ip != CEE_CALLI && *ip != CEE_CALLVIRT))
5966 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("tail prefix must be used only with call opcodes at 0x%04x", ip_offset));
5967 break;
5969 case CEE_INITOBJ:
5970 code_bounds_check (5);
5971 do_initobj (&ctx, read32 (ip + 1));
5972 ip += 5;
5973 break;
5975 case CEE_CONSTRAINED_:
5976 code_bounds_check (5);
5977 ctx.constrained_type = get_boxable_mono_type (&ctx, read32 (ip + 1), "constrained.");
5978 prefix |= PREFIX_CONSTRAINED;
5979 ip += 5;
5980 break;
5982 case CEE_READONLY_:
5983 prefix |= PREFIX_READONLY;
5984 ip++;
5985 break;
5987 case CEE_CPBLK:
5988 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5989 if (!check_underflow (&ctx, 3))
5990 break;
5991 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction cpblk is not verifiable at 0x%04x", ctx.ip_offset));
5992 ip++;
5993 break;
5995 case CEE_INITBLK:
5996 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5997 if (!check_underflow (&ctx, 3))
5998 break;
5999 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction initblk is not verifiable at 0x%04x", ctx.ip_offset));
6000 ip++;
6001 break;
6003 case CEE_NO_:
6004 ip += 2;
6005 break;
6006 case CEE_RETHROW:
6007 if (!is_correct_rethrow (ctx.header, ip_offset))
6008 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("rethrow must be used inside a catch handler at 0x%04x", ctx.ip_offset));
6009 ctx.eval.size = 0;
6010 start = 1;
6011 ++ip;
6012 break;
6014 case CEE_SIZEOF:
6015 code_bounds_check (5);
6016 do_sizeof (&ctx, read32 (ip + 1));
6017 ip += 5;
6018 break;
6020 case CEE_REFANYTYPE:
6021 do_refanytype (&ctx);
6022 ++ip;
6023 break;
6025 default:
6026 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction FE %x at 0x%04x", *ip, ctx.ip_offset));
6027 ++ip;
6029 break;
6031 default:
6032 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ctx.ip_offset));
6033 ++ip;
6036 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
6037 if (prefix) {
6038 if (!ctx.prefix_set) //first prefix
6039 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
6040 ctx.prefix_set |= prefix;
6041 ctx.has_flags = TRUE;
6042 prefix = 0;
6043 } else {
6044 if (!ctx.has_flags)
6045 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
6047 if (ctx.prefix_set & PREFIX_CONSTRAINED)
6048 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after constrained prefix at 0x%04x", ctx.ip_offset));
6049 if (ctx.prefix_set & PREFIX_READONLY)
6050 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after readonly prefix at 0x%04x", ctx.ip_offset));
6051 if (ctx.prefix_set & PREFIX_VOLATILE)
6052 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after volatile prefix at 0x%04x", ctx.ip_offset));
6053 if (ctx.prefix_set & PREFIX_UNALIGNED)
6054 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after unaligned prefix at 0x%04x", ctx.ip_offset));
6055 ctx.prefix_set = prefix = 0;
6056 ctx.has_flags = FALSE;
6060 * if ip != end we overflowed: mark as error.
6062 if ((ip != end || !start) && ctx.verifiable && !ctx.list) {
6063 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Run ahead of method code at 0x%04x", ip_offset));
6066 /*We should guard against the last decoded opcode, otherwise we might add errors that doesn't make sense.*/
6067 for (i = 0; i < ctx.code_size && i < ip_offset; ++i) {
6068 if (ctx.code [i].flags & IL_CODE_FLAG_WAS_TARGET) {
6069 if (!(ctx.code [i].flags & IL_CODE_FLAG_SEEN))
6070 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or exception block target middle of instruction at 0x%04x", i));
6072 if (ctx.code [i].flags & IL_CODE_DELEGATE_SEQUENCE)
6073 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Branch to delegate code sequence at 0x%04x", i));
6075 if ((ctx.code [i].flags & IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL) && ctx.has_this_store)
6076 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at 0x%04x", i));
6078 if ((ctx.code [i].flags & IL_CODE_CALL_NONFINAL_VIRTUAL) && ctx.has_this_store)
6079 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));
6082 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) {
6083 char *method_name = mono_method_full_name (ctx.method, TRUE);
6084 char *type = mono_type_get_full_name (ctx.method->klass);
6085 if (m_class_get_parent (ctx.method->klass) && mono_class_has_failure (m_class_get_parent (ctx.method->klass)))
6086 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));
6087 else
6088 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Constructor %s for type %s not calling base type ctor.", method_name, type));
6089 g_free (method_name);
6090 g_free (type);
6093 cleanup:
6094 if (ctx.code) {
6095 for (i = 0; i < ctx.header->code_size; ++i) {
6096 if (ctx.code [i].stack)
6097 g_free (ctx.code [i].stack);
6101 for (tmp = ctx.funptrs; tmp; tmp = tmp->next)
6102 g_free (tmp->data);
6103 g_slist_free (ctx.funptrs);
6105 for (tmp = ctx.exception_types; tmp; tmp = tmp->next)
6106 mono_metadata_free_type ((MonoType *)tmp->data);
6107 g_slist_free (ctx.exception_types);
6109 for (i = 0; i < ctx.num_locals; ++i) {
6110 if (ctx.locals [i])
6111 mono_metadata_free_type (ctx.locals [i]);
6113 for (i = 0; i < ctx.max_args; ++i) {
6114 if (ctx.params [i])
6115 mono_metadata_free_type (ctx.params [i]);
6118 if (ctx.eval.stack)
6119 g_free (ctx.eval.stack);
6120 if (ctx.code)
6121 g_free (ctx.code);
6122 g_free (ctx.locals);
6123 g_free (ctx.locals_verification_state);
6124 g_free (ctx.params);
6125 mono_basic_block_free (original_bb);
6126 mono_metadata_free_mh (ctx.header);
6128 finish_collect_stats ();
6129 return ctx.list;
6132 char*
6133 mono_verify_corlib ()
6135 /* This is a public API function so cannot be removed */
6136 return NULL;
6140 * mono_verifier_is_enabled_for_method:
6141 * \param method the method to probe
6142 * \returns TRUE if \p method needs to be verified.
6144 gboolean
6145 mono_verifier_is_enabled_for_method (MonoMethod *method)
6147 return mono_verifier_is_enabled_for_class (method->klass) && (method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD);
6151 * mono_verifier_is_enabled_for_class:
6152 * \param klass The \c MonoClass to probe
6153 * \returns TRUE if \p klass need to be verified.
6155 gboolean
6156 mono_verifier_is_enabled_for_class (MonoClass *klass)
6158 MonoImage *image = m_class_get_image (klass);
6159 return verify_all || (verifier_mode > MONO_VERIFIER_MODE_OFF && !(image->assembly && image->assembly->in_gac) && image != mono_defaults.corlib);
6162 gboolean
6163 mono_verifier_is_enabled_for_image (MonoImage *image)
6165 return verify_all || verifier_mode > MONO_VERIFIER_MODE_OFF;
6169 * Dynamic methods are not considered full trust since if the user is trusted and need to
6170 * generate unsafe code, make the method skip verification - this is a known good way to do it.
6172 gboolean
6173 mono_verifier_is_method_full_trust (MonoMethod *method)
6175 return mono_verifier_is_class_full_trust (method->klass) && !method_is_dynamic (method);
6179 * Returns if @klass is under full trust or not.
6181 * TODO This code doesn't take CAS into account.
6183 * Under verify_all all user code must be verifiable if no security option was set
6186 gboolean
6187 mono_verifier_is_class_full_trust (MonoClass *klass)
6189 MonoImage *image = m_class_get_image (klass);
6190 /* under CoreCLR code is trusted if it is part of the "platform" otherwise all code inside the GAC is trusted */
6191 gboolean trusted_location = !mono_security_core_clr_enabled () ?
6192 (image->assembly && image->assembly->in_gac) : mono_security_core_clr_is_platform_image (image);
6194 if (verify_all && verifier_mode == MONO_VERIFIER_MODE_OFF)
6195 return trusted_location || image == mono_defaults.corlib;
6196 return verifier_mode < MONO_VERIFIER_MODE_VERIFIABLE || trusted_location || image == mono_defaults.corlib;
6199 GSList*
6200 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility, gboolean is_fulltrust)
6202 return mono_method_verify (method,
6203 (verifier_mode != MONO_VERIFIER_MODE_STRICT ? MONO_VERIFY_NON_STRICT: 0)
6204 | (!is_fulltrust && !mono_verifier_is_method_full_trust (method) ? MONO_VERIFY_FAIL_FAST : 0)
6205 | (skip_visibility ? MONO_VERIFY_SKIP_VISIBILITY : 0));
6208 static int
6209 get_field_end (MonoClassField *field)
6211 int align;
6212 int size = mono_type_size (field->type, &align);
6213 if (size == 0)
6214 size = 4; /*FIXME Is this a safe bet?*/
6215 return size + field->offset;
6218 static gboolean
6219 verify_class_for_overlapping_reference_fields (MonoClass *klass)
6221 int i = 0, j;
6222 gpointer iter = NULL;
6223 MonoClassField *field;
6224 gboolean is_fulltrust = mono_verifier_is_class_full_trust (klass);
6225 /*We can't skip types with !has_references since this is calculated after we have run.*/
6226 if (!mono_class_is_explicit_layout (klass))
6227 return TRUE;
6230 /*We must check for stuff overlapping reference fields.
6231 The outer loop uses mono_class_get_fields_internal to ensure that MonoClass:fields get inited.
6233 while ((field = mono_class_get_fields_internal (klass, &iter))) {
6234 int fieldEnd = get_field_end (field);
6235 gboolean is_valuetype = !MONO_TYPE_IS_REFERENCE (field->type);
6236 ++i;
6238 if (mono_field_is_deleted (field) || (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
6239 continue;
6241 int fcount = mono_class_get_field_count (klass);
6242 MonoClassField *klass_fields = m_class_get_fields (klass);
6243 for (j = i; j < fcount; ++j) {
6244 MonoClassField *other = &klass_fields [j];
6245 int otherEnd = get_field_end (other);
6246 if (mono_field_is_deleted (other) || (is_valuetype && !MONO_TYPE_IS_REFERENCE (other->type)) || (other->type->attrs & FIELD_ATTRIBUTE_STATIC))
6247 continue;
6249 if (!is_valuetype && MONO_TYPE_IS_REFERENCE (other->type) && field->offset == other->offset && is_fulltrust)
6250 continue;
6252 if ((otherEnd > field->offset && otherEnd <= fieldEnd) || (other->offset >= field->offset && other->offset < fieldEnd))
6253 return FALSE;
6256 return TRUE;
6259 static guint
6260 field_hash (gconstpointer key)
6262 const MonoClassField *field = (const MonoClassField *)key;
6263 return g_str_hash (field->name) ^ mono_metadata_type_hash (field->type); /**/
6266 static gboolean
6267 field_equals (gconstpointer _a, gconstpointer _b)
6269 const MonoClassField *a = (const MonoClassField *)_a;
6270 const MonoClassField *b = (const MonoClassField *)_b;
6271 return !strcmp (a->name, b->name) && mono_metadata_type_equal (a->type, b->type);
6275 static gboolean
6276 verify_class_fields (MonoClass *klass)
6278 gpointer iter = NULL;
6279 MonoClassField *field;
6280 MonoGenericContext *context = mono_class_get_context (klass);
6281 GHashTable *unique_fields = g_hash_table_new_full (&field_hash, &field_equals, NULL, NULL);
6282 if (mono_class_is_gtd (klass))
6283 context = &mono_class_get_generic_container (klass)->context;
6285 while ((field = mono_class_get_fields_internal (klass, &iter)) != NULL) {
6286 if (!mono_type_is_valid_type_in_context (field->type, context)) {
6287 g_hash_table_destroy (unique_fields);
6288 return FALSE;
6290 if (g_hash_table_lookup (unique_fields, field)) {
6291 g_hash_table_destroy (unique_fields);
6292 return FALSE;
6294 g_hash_table_insert (unique_fields, field, field);
6296 g_hash_table_destroy (unique_fields);
6297 return TRUE;
6300 static gboolean
6301 verify_interfaces (MonoClass *klass)
6303 int i;
6304 guint16 klass_interface_count = m_class_get_interface_count (klass);
6305 MonoClass **klass_interfaces = m_class_get_interfaces (klass);
6306 for (i = 0; i < klass_interface_count; ++i) {
6307 MonoClass *iface = klass_interfaces [i];
6308 if (!mono_class_get_flags (iface))
6309 return FALSE;
6311 return TRUE;
6314 static gboolean
6315 verify_valuetype_layout_with_target (MonoClass *klass, MonoClass *target_class)
6317 int type;
6318 gpointer iter = NULL;
6319 MonoClassField *field;
6320 MonoClass *field_class;
6322 if (!m_class_is_valuetype (klass))
6323 return TRUE;
6325 type = m_class_get_byval_arg (klass)->type;
6326 /*primitive type fields are not properly decoded*/
6327 if ((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_R8) || (type >= MONO_TYPE_I && type <= MONO_TYPE_U))
6328 return TRUE;
6330 while ((field = mono_class_get_fields_internal (klass, &iter)) != NULL) {
6331 if (!field->type)
6332 return FALSE;
6334 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
6335 continue;
6337 field_class = mono_class_get_generic_type_definition (mono_class_from_mono_type_internal (field->type));
6339 if (field_class == target_class || klass == field_class || !verify_valuetype_layout_with_target (field_class, target_class))
6340 return FALSE;
6343 return TRUE;
6346 static gboolean
6347 verify_valuetype_layout (MonoClass *klass)
6349 gboolean res;
6350 res = verify_valuetype_layout_with_target (klass, klass);
6351 return res;
6354 static gboolean
6355 recursive_mark_constraint_args (MonoBitSet *used_args, MonoGenericContainer *gc, MonoType *type)
6357 int idx;
6358 MonoClass **constraints;
6359 MonoGenericParamInfo *param_info;
6361 g_assert (mono_type_is_generic_argument (type));
6363 idx = mono_type_get_generic_param_num (type);
6364 if (mono_bitset_test_fast (used_args, idx))
6365 return FALSE;
6367 mono_bitset_set_fast (used_args, idx);
6368 param_info = mono_generic_container_get_param_info (gc, idx);
6370 if (!param_info->constraints)
6371 return TRUE;
6373 for (constraints = param_info->constraints; *constraints; ++constraints) {
6374 MonoClass *ctr = *constraints;
6375 MonoType *constraint_type = m_class_get_byval_arg (ctr);
6377 if (mono_type_is_generic_argument (constraint_type) && !recursive_mark_constraint_args (used_args, gc, constraint_type))
6378 return FALSE;
6380 return TRUE;
6383 static gboolean
6384 verify_generic_parameters (MonoClass *klass)
6386 int i;
6387 MonoGenericContainer *gc = mono_class_get_generic_container (klass);
6388 MonoBitSet *used_args = mono_bitset_new (gc->type_argc, 0);
6390 for (i = 0; i < gc->type_argc; ++i) {
6391 MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
6392 MonoClass **constraints;
6394 if (!param_info->constraints)
6395 continue;
6397 mono_bitset_clear_all (used_args);
6398 mono_bitset_set_fast (used_args, i);
6400 for (constraints = param_info->constraints; *constraints; ++constraints) {
6401 MonoClass *ctr = *constraints;
6402 MonoType *constraint_type = m_class_get_byval_arg (ctr);
6404 if (!mono_class_can_access_class (klass, ctr))
6405 goto fail;
6407 if (!mono_type_is_valid_type_in_context (constraint_type, &gc->context))
6408 goto fail;
6410 if (mono_type_is_generic_argument (constraint_type) && !recursive_mark_constraint_args (used_args, gc, constraint_type))
6411 goto fail;
6412 if (mono_class_is_ginst (ctr) && !mono_class_is_valid_generic_instantiation (NULL, ctr))
6413 goto fail;
6416 mono_bitset_free (used_args);
6417 return TRUE;
6419 fail:
6420 mono_bitset_free (used_args);
6421 return FALSE;
6425 * Check if the class is verifiable.
6427 * Right now there are no conditions that make a class a valid but not verifiable. Both overlapping reference
6428 * field and invalid generic instantiation are fatal errors.
6430 * This method must be safe to be called from mono_class_init_internal and all code must be carefull about that.
6433 gboolean
6434 mono_verifier_verify_class (MonoClass *klass)
6436 MonoClass *klass_parent = m_class_get_parent (klass);
6437 /*Neither <Module>, object or ifaces have parent.*/
6438 if (!klass_parent &&
6439 klass != mono_defaults.object_class &&
6440 !MONO_CLASS_IS_INTERFACE_INTERNAL (klass) &&
6441 (!image_is_dynamic (m_class_get_image (klass)) && m_class_get_type_token (klass) != 0x2000001)) /*<Module> is the first type in the assembly*/
6442 return FALSE;
6443 if (m_class_get_parent (klass)) {
6444 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass_parent))
6445 return FALSE;
6446 if (!mono_class_is_ginst (klass) && mono_class_is_gtd (klass_parent))
6447 return FALSE;
6448 if (mono_class_is_ginst (klass_parent) && !mono_class_is_ginst (klass)) {
6449 MonoGenericContext *context = mono_class_get_context (klass);
6450 if (mono_class_is_gtd (klass))
6451 context = &mono_class_get_generic_container (klass)->context;
6452 if (!mono_type_is_valid_type_in_context (m_class_get_byval_arg (klass_parent), context))
6453 return FALSE;
6456 if (mono_class_is_gtd (klass) && (mono_class_is_explicit_layout (klass)))
6457 return FALSE;
6458 if (mono_class_is_gtd (klass) && !verify_generic_parameters (klass))
6459 return FALSE;
6460 if (!verify_class_for_overlapping_reference_fields (klass))
6461 return FALSE;
6462 if (mono_class_is_ginst (klass) && !mono_class_is_valid_generic_instantiation (NULL, klass))
6463 return FALSE;
6464 if (!mono_class_is_ginst (klass) && !verify_class_fields (klass))
6465 return FALSE;
6466 if (m_class_is_valuetype (klass) && !verify_valuetype_layout (klass))
6467 return FALSE;
6468 if (!verify_interfaces (klass))
6469 return FALSE;
6470 return TRUE;
6473 #else
6475 gboolean
6476 mono_verifier_verify_class (MonoClass *klass)
6478 /* The verifier was disabled at compile time */
6479 return TRUE;
6482 GSList*
6483 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility, gboolean is_fulltrust)
6485 /* The verifier was disabled at compile time */
6486 return NULL;
6489 gboolean
6490 mono_verifier_is_class_full_trust (MonoClass *klass)
6492 /* The verifier was disabled at compile time */
6493 return TRUE;
6496 gboolean
6497 mono_verifier_is_method_full_trust (MonoMethod *method)
6499 /* The verifier was disabled at compile time */
6500 return TRUE;
6503 gboolean
6504 mono_verifier_is_enabled_for_image (MonoImage *image)
6506 /* The verifier was disabled at compile time */
6507 return FALSE;
6510 gboolean
6511 mono_verifier_is_enabled_for_class (MonoClass *klass)
6513 /* The verifier was disabled at compile time */
6514 return FALSE;
6517 gboolean
6518 mono_verifier_is_enabled_for_method (MonoMethod *method)
6520 /* The verifier was disabled at compile time */
6521 return FALSE;
6524 GSList*
6525 mono_method_verify (MonoMethod *method, int level)
6527 /* The verifier was disabled at compile time */
6528 return NULL;
6531 void
6532 mono_free_verify_list (GSList *list)
6534 /* The verifier was disabled at compile time */
6535 /* will always be null if verifier is disabled */
6538 #endif