[packaging] Bundle the msvc compiled monograph.exe on Windows
[mono-project.git] / mono / metadata / verify.c
blobf8bc9652f645248e37316f5116c077fbf1838b7d
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 <string.h>
35 #include <ctype.h>
37 static MiniVerifierMode verifier_mode = MONO_VERIFIER_MODE_OFF;
38 static gboolean verify_all = FALSE;
41 * Set the desired level of checks for the verfier.
44 void
45 mono_verifier_set_mode (MiniVerifierMode mode)
47 verifier_mode = mode;
50 void
51 mono_verifier_enable_verify_all ()
53 verify_all = TRUE;
56 #ifndef DISABLE_VERIFIER
58 * Pull the list of opcodes
60 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
61 a = i,
63 enum {
64 #include "mono/cil/opcode.def"
65 LAST = 0xff
67 #undef OPDEF
69 #ifdef MONO_VERIFIER_DEBUG
70 #define VERIFIER_DEBUG(code) do { code } while (0)
71 #else
72 #define VERIFIER_DEBUG(code)
73 #endif
75 //////////////////////////////////////////////////////////////////
76 #define IS_STRICT_MODE(ctx) (((ctx)->level & MONO_VERIFY_NON_STRICT) == 0)
77 #define IS_FAIL_FAST_MODE(ctx) (((ctx)->level & MONO_VERIFY_FAIL_FAST) == MONO_VERIFY_FAIL_FAST)
78 #define IS_SKIP_VISIBILITY(ctx) (((ctx)->level & MONO_VERIFY_SKIP_VISIBILITY) == MONO_VERIFY_SKIP_VISIBILITY)
79 #define IS_REPORT_ALL_ERRORS(ctx) (((ctx)->level & MONO_VERIFY_REPORT_ALL_ERRORS) == MONO_VERIFY_REPORT_ALL_ERRORS)
80 #define CLEAR_PREFIX(ctx, prefix) do { (ctx)->prefix_set &= ~(prefix); } while (0)
81 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
82 do { \
83 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
84 vinfo->info.status = __status; \
85 vinfo->info.message = ( __msg ); \
86 vinfo->exception_type = (__exception); \
87 (__ctx)->list = g_slist_prepend ((__ctx)->list, vinfo); \
88 } while (0)
90 //TODO support MONO_VERIFY_REPORT_ALL_ERRORS
91 #define ADD_VERIFY_ERROR(__ctx, __msg) \
92 do { \
93 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
94 (__ctx)->valid = 0; \
95 } while (0)
97 #define CODE_NOT_VERIFIABLE(__ctx, __msg) \
98 do { \
99 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
100 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, MONO_EXCEPTION_UNVERIFIABLE_IL); \
101 (__ctx)->verifiable = 0; \
102 if (IS_FAIL_FAST_MODE (__ctx)) \
103 (__ctx)->valid = 0; \
105 } while (0)
107 #define ADD_VERIFY_ERROR2(__ctx, __msg, __exception) \
108 do { \
109 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, __exception); \
110 (__ctx)->valid = 0; \
111 } while (0)
113 #define CODE_NOT_VERIFIABLE2(__ctx, __msg, __exception) \
114 do { \
115 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
116 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, __exception); \
117 (__ctx)->verifiable = 0; \
118 if (IS_FAIL_FAST_MODE (__ctx)) \
119 (__ctx)->valid = 0; \
121 } while (0)
123 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
124 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
126 #if SIZEOF_VOID_P == 4
127 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
128 #else
129 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
130 #endif
132 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
133 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
135 /*Flags to be used with ILCodeDesc::flags */
136 enum {
137 /*Instruction has not been processed.*/
138 IL_CODE_FLAG_NOT_PROCESSED = 0,
139 /*Instruction was decoded by mono_method_verify loop.*/
140 IL_CODE_FLAG_SEEN = 1,
141 /*Instruction was target of a branch or is at a protected block boundary.*/
142 IL_CODE_FLAG_WAS_TARGET = 2,
143 /*Used by stack_init to avoid double initialize each entry.*/
144 IL_CODE_FLAG_STACK_INITED = 4,
145 /*Used by merge_stacks to decide if it should just copy the eval stack.*/
146 IL_CODE_STACK_MERGED = 8,
147 /*This instruction is part of the delegate construction sequence, it cannot be target of a branch.*/
148 IL_CODE_DELEGATE_SEQUENCE = 0x10,
149 /*This is a delegate created from a ldftn to a non final virtual method*/
150 IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL = 0x20,
151 /*This is a call to a non final virtual method*/
152 IL_CODE_CALL_NONFINAL_VIRTUAL = 0x40,
155 typedef enum {
156 RESULT_VALID,
157 RESULT_UNVERIFIABLE,
158 RESULT_INVALID
159 } verify_result_t;
161 typedef struct {
162 MonoType *type;
163 int stype;
164 MonoMethod *method;
165 } ILStackDesc;
168 typedef struct {
169 ILStackDesc *stack;
170 guint16 size, max_size;
171 guint16 flags;
172 } ILCodeDesc;
174 typedef struct {
175 int max_args;
176 int max_stack;
177 int verifiable;
178 int valid;
179 int level;
181 int code_size;
182 ILCodeDesc *code;
183 ILCodeDesc eval;
185 MonoType **params;
186 GSList *list;
187 /*Allocated fnptr MonoType that should be freed by us.*/
188 GSList *funptrs;
189 /*Type dup'ed exception types from catch blocks.*/
190 GSList *exception_types;
192 int num_locals;
193 MonoType **locals;
194 char *locals_verification_state;
196 /*TODO get rid of target here, need_merge in mono_method_verify and hoist the merging code in the branching code*/
197 int target;
199 guint32 ip_offset;
200 MonoMethodSignature *signature;
201 MonoMethodHeader *header;
203 MonoGenericContext *generic_context;
204 MonoImage *image;
205 MonoMethod *method;
207 /*This flag helps solving a corner case of delegate verification in that you cannot have a "starg 0"
208 *on a method that creates a delegate for a non-final virtual method using ldftn*/
209 gboolean has_this_store;
211 /*This flag is used to control if the contructor of the parent class has been called.
212 *If the this pointer is pushed on the eval stack and it's a reference type constructor and
213 * super_ctor_called is false, the uninitialized flag is set on the pushed value.
215 * Poping an uninitialized this ptr from the eval stack is an unverifiable operation unless
216 * the safe variant is used. Only a few opcodes can use it : dup, pop, ldfld, stfld and call to a constructor.
218 gboolean super_ctor_called;
220 guint32 prefix_set;
221 gboolean has_flags;
222 MonoType *constrained_type;
223 } VerifyContext;
225 static void
226 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external);
228 static int
229 get_stack_type (MonoType *type);
231 static gboolean
232 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn);
234 static gboolean
235 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass);
237 static gboolean
238 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method);
240 static MonoGenericParam*
241 verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type);
243 static gboolean
244 verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate);
245 //////////////////////////////////////////////////////////////////
249 enum {
250 TYPE_INV = 0, /* leave at 0. */
251 TYPE_I4 = 1,
252 TYPE_I8 = 2,
253 TYPE_NATIVE_INT = 3,
254 TYPE_R8 = 4,
255 /* Used by operator tables to resolve pointer types (managed & unmanaged) and by unmanaged pointer types*/
256 TYPE_PTR = 5,
257 /* value types and classes */
258 TYPE_COMPLEX = 6,
259 /* Number of types, used to define the size of the tables*/
260 TYPE_MAX = 6,
262 /* Used by tables to signal that a result is not verifiable*/
263 NON_VERIFIABLE_RESULT = 0x80,
265 /*Mask used to extract just the type, excluding flags */
266 TYPE_MASK = 0x0F,
268 /* The stack type is a managed pointer, unmask the value to res */
269 POINTER_MASK = 0x100,
271 /*Stack type with the pointer mask*/
272 RAW_TYPE_MASK = 0x10F,
274 /* Controlled Mutability Manager Pointer */
275 CMMP_MASK = 0x200,
277 /* The stack type is a null literal*/
278 NULL_LITERAL_MASK = 0x400,
280 /**Used by ldarg.0 and family to let delegate verification happens.*/
281 THIS_POINTER_MASK = 0x800,
283 /**Signals that this is a boxed value type*/
284 BOXED_MASK = 0x1000,
286 /*This is an unitialized this ref*/
287 UNINIT_THIS_MASK = 0x2000,
289 /* This is a safe to return byref */
290 SAFE_BYREF_MASK = 0x4000,
293 static const char* const
294 type_names [TYPE_MAX + 1] = {
295 "Invalid",
296 "Int32",
297 "Int64",
298 "Native Int",
299 "Float64",
300 "Native Pointer",
301 "Complex"
304 enum {
305 PREFIX_UNALIGNED = 1,
306 PREFIX_VOLATILE = 2,
307 PREFIX_TAIL = 4,
308 PREFIX_CONSTRAINED = 8,
309 PREFIX_READONLY = 16
311 //////////////////////////////////////////////////////////////////
313 #ifdef ENABLE_VERIFIER_STATS
315 #define _MEM_ALLOC(amt) do { allocated_memory += (amt); working_set += (amt); } while (0)
316 #define _MEM_FREE(amt) do { working_set -= (amt); } while (0)
318 static int allocated_memory;
319 static int working_set;
320 static int max_allocated_memory;
321 static int max_working_set;
322 static int total_allocated_memory;
324 static void
325 finish_collect_stats (void)
327 max_allocated_memory = MAX (max_allocated_memory, allocated_memory);
328 max_working_set = MAX (max_working_set, working_set);
329 total_allocated_memory += allocated_memory;
330 allocated_memory = working_set = 0;
333 static void
334 init_verifier_stats (void)
336 static gboolean inited;
337 if (!inited) {
338 inited = TRUE;
339 mono_counters_register ("Maximum memory allocated during verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &max_allocated_memory);
340 mono_counters_register ("Maximum memory used during verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &max_working_set);
341 mono_counters_register ("Total memory allocated for verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &total_allocated_memory);
345 #else
347 #define _MEM_ALLOC(amt) do {} while (0)
348 #define _MEM_FREE(amt) do { } while (0)
350 #define finish_collect_stats()
351 #define init_verifier_stats()
353 #endif
356 //////////////////////////////////////////////////////////////////
359 /*Token validation macros and functions */
360 #define IS_MEMBER_REF(token) (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
361 #define IS_METHOD_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
362 #define IS_METHOD_SPEC(token) (mono_metadata_token_table (token) == MONO_TABLE_METHODSPEC)
363 #define IS_FIELD_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_FIELD)
365 #define IS_TYPE_REF(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPEREF)
366 #define IS_TYPE_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPEDEF)
367 #define IS_TYPE_SPEC(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC)
368 #define IS_METHOD_DEF_OR_REF_OR_SPEC(token) (IS_METHOD_DEF (token) || IS_MEMBER_REF (token) || IS_METHOD_SPEC (token))
369 #define IS_TYPE_DEF_OR_REF_OR_SPEC(token) (IS_TYPE_DEF (token) || IS_TYPE_REF (token) || IS_TYPE_SPEC (token))
370 #define IS_FIELD_DEF_OR_REF(token) (IS_FIELD_DEF (token) || IS_MEMBER_REF (token))
373 * Verify if @token refers to a valid row on int's table.
375 static gboolean
376 token_bounds_check (MonoImage *image, guint32 token)
378 if (image_is_dynamic (image))
379 return mono_dynamic_image_is_valid_token ((MonoDynamicImage*)image, token);
380 return image->tables [mono_metadata_token_table (token)].rows >= mono_metadata_token_index (token) && mono_metadata_token_index (token) > 0;
383 static MonoType *
384 mono_type_create_fnptr_from_mono_method (VerifyContext *ctx, MonoMethod *method)
386 MonoType *res = g_new0 (MonoType, 1);
387 _MEM_ALLOC (sizeof (MonoType));
389 //FIXME use mono_method_get_signature_full
390 res->data.method = mono_method_signature (method);
391 res->type = MONO_TYPE_FNPTR;
392 ctx->funptrs = g_slist_prepend (ctx->funptrs, res);
393 return res;
397 * mono_type_is_enum_type:
399 * Returns: TRUE if @type is an enum type.
401 static gboolean
402 mono_type_is_enum_type (MonoType *type)
404 if (type->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (type->data.klass))
405 return TRUE;
406 if (type->type == MONO_TYPE_GENERICINST && m_class_is_enumtype (type->data.generic_class->container_class))
407 return TRUE;
408 return FALSE;
412 * mono_type_is_value_type:
414 * Returns: TRUE if @type is named after @namespace.@name.
417 static gboolean
418 mono_type_is_value_type (MonoType *type, const char *namespace_, const char *name)
420 return type->type == MONO_TYPE_VALUETYPE &&
421 !strcmp (namespace_, m_class_get_name_space (type->data.klass)) &&
422 !strcmp (name, m_class_get_name (type->data.klass));
426 * Returns TURE if @type is VAR or MVAR
428 static gboolean
429 mono_type_is_generic_argument (MonoType *type)
431 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
435 * mono_type_get_underlying_type_any:
437 * This functions is just like mono_type_get_underlying_type but it doesn't care if the type is byref.
439 * Returns the underlying type of @type regardless if it is byref or not.
441 static MonoType*
442 mono_type_get_underlying_type_any (MonoType *type)
444 if (type->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (type->data.klass))
445 return mono_class_enum_basetype (type->data.klass);
446 if (type->type == MONO_TYPE_GENERICINST && m_class_is_enumtype (type->data.generic_class->container_class))
447 return mono_class_enum_basetype (type->data.generic_class->container_class);
448 return type;
451 static G_GNUC_UNUSED const char*
452 mono_type_get_stack_name (MonoType *type)
454 return type_names [get_stack_type (type) & TYPE_MASK];
457 #define CTOR_REQUIRED_FLAGS (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_RT_SPECIAL_NAME)
458 #define CTOR_INVALID_FLAGS (METHOD_ATTRIBUTE_STATIC)
460 static gboolean
461 mono_method_is_constructor (MonoMethod *method)
463 return ((method->flags & CTOR_REQUIRED_FLAGS) == CTOR_REQUIRED_FLAGS &&
464 !(method->flags & CTOR_INVALID_FLAGS) &&
465 !strcmp (".ctor", method->name));
468 static gboolean
469 mono_class_has_default_constructor (MonoClass *klass)
471 MonoMethod *method;
472 int i;
474 mono_class_setup_methods (klass);
475 if (mono_class_has_failure (klass))
476 return FALSE;
478 int mcount = mono_class_get_method_count (klass);
479 MonoMethod **klass_methods = m_class_get_methods (klass);
480 for (i = 0; i < mcount; ++i) {
481 method = klass_methods [i];
482 if (mono_method_is_constructor (method) &&
483 mono_method_signature (method) &&
484 mono_method_signature (method)->param_count == 0 &&
485 (method->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC)
486 return TRUE;
488 return FALSE;
492 * Verify if @type is valid for the given @ctx verification context.
493 * this function checks for VAR and MVAR types that are invalid under the current verifier,
495 static gboolean
496 mono_type_is_valid_type_in_context_full (MonoType *type, MonoGenericContext *context, gboolean check_gtd)
498 int i;
499 MonoGenericInst *inst;
501 switch (type->type) {
502 case MONO_TYPE_VAR:
503 case MONO_TYPE_MVAR:
504 if (!context)
505 return FALSE;
506 inst = type->type == MONO_TYPE_VAR ? context->class_inst : context->method_inst;
507 if (!inst || mono_type_get_generic_param_num (type) >= inst->type_argc)
508 return FALSE;
509 break;
510 case MONO_TYPE_SZARRAY:
511 return mono_type_is_valid_type_in_context_full (m_class_get_byval_arg (type->data.klass), context, check_gtd);
512 case MONO_TYPE_ARRAY:
513 return mono_type_is_valid_type_in_context_full (m_class_get_byval_arg (type->data.array->eklass), context, check_gtd);
514 case MONO_TYPE_PTR:
515 return mono_type_is_valid_type_in_context_full (type->data.type, context, check_gtd);
516 case MONO_TYPE_GENERICINST:
517 inst = type->data.generic_class->context.class_inst;
518 if (!inst->is_open)
519 break;
520 for (i = 0; i < inst->type_argc; ++i)
521 if (!mono_type_is_valid_type_in_context_full (inst->type_argv [i], context, check_gtd))
522 return FALSE;
523 break;
524 case MONO_TYPE_CLASS:
525 case MONO_TYPE_VALUETYPE: {
526 MonoClass *klass = type->data.klass;
527 MonoType *klass_byval_arg = m_class_get_byval_arg (klass);
529 * It's possible to encode generic'sh types in such a way that they disguise themselves as class or valuetype.
530 * Fixing the type decoding is really tricky since under some cases this behavior is needed, for example, to
531 * have a 'class' type pointing to a 'genericinst' class.
533 * For the runtime these non canonical (weird) encodings work fine, the worst they can cause is some
534 * reflection oddities which are harmless - to security at least.
536 if (klass_byval_arg->type != type->type)
537 return mono_type_is_valid_type_in_context_full (klass_byval_arg, context, check_gtd);
539 if (check_gtd && mono_class_is_gtd (klass))
540 return FALSE;
541 break;
543 default:
544 break;
546 return TRUE;
549 static gboolean
550 mono_type_is_valid_type_in_context (MonoType *type, MonoGenericContext *context)
552 return mono_type_is_valid_type_in_context_full (type, context, FALSE);
555 /*This function returns NULL if the type is not instantiatable*/
556 static MonoType*
557 verifier_inflate_type (VerifyContext *ctx, MonoType *type, MonoGenericContext *context)
559 ERROR_DECL (error);
560 MonoType *result;
562 result = mono_class_inflate_generic_type_checked (type, context, error);
563 if (!mono_error_ok (error)) {
564 mono_error_cleanup (error);
565 return NULL;
567 return result;
570 /*A side note here. We don't need to check if arguments are broken since this
571 is only need to be done by the runtime before realizing the type.
573 static gboolean
574 is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
576 ERROR_DECL (error);
577 int i;
579 if (ginst->type_argc != gc->type_argc)
580 return FALSE;
582 for (i = 0; i < gc->type_argc; ++i) {
583 MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
584 MonoClass *paramClass;
585 MonoClass **constraints;
586 MonoType *param_type = ginst->type_argv [i];
588 /*it's not our job to validate type variables*/
589 if (mono_type_is_generic_argument (param_type))
590 continue;
592 paramClass = mono_class_from_mono_type (param_type);
595 /* A GTD can't be a generic argument.
597 * Due to how types are encoded we must check for the case of a genericinst MonoType and GTD MonoClass.
598 * This happens in cases such as: class Foo<T> { void X() { new Bar<T> (); } }
600 * Open instantiations can have GTDs as this happens when one type is instantiated with others params
601 * and the former has an expansion into the later. For example:
602 * class B<K> {}
603 * class A<T>: B<K> {}
604 * The type A <K> has a parent B<K>, that is inflated into the GTD B<>.
605 * Since A<K> is open, thus not instantiatable, this is valid.
607 if (mono_class_is_gtd (paramClass) && param_type->type != MONO_TYPE_GENERICINST && !ginst->is_open)
608 return FALSE;
610 /*it's not safe to call mono_class_init from here*/
611 if (mono_class_is_ginst (paramClass) && !m_class_is_inited (paramClass)) {
612 if (!mono_class_is_valid_generic_instantiation (NULL, paramClass))
613 return FALSE;
616 if (!param_info->constraints && !(param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK))
617 continue;
619 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && (!m_class_is_valuetype (paramClass) || mono_class_is_nullable (paramClass)))
620 return FALSE;
622 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && m_class_is_valuetype (paramClass))
623 return FALSE;
625 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !m_class_is_valuetype (paramClass) && !mono_class_has_default_constructor (paramClass))
626 return FALSE;
628 if (!param_info->constraints)
629 continue;
631 for (constraints = param_info->constraints; *constraints; ++constraints) {
632 MonoClass *ctr = *constraints;
633 MonoType *inflated;
635 inflated = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (ctr), context, error);
636 if (!mono_error_ok (error)) {
637 mono_error_cleanup (error);
638 return FALSE;
640 ctr = mono_class_from_mono_type (inflated);
641 mono_metadata_free_type (inflated);
643 /*FIXME maybe we need the same this as verifier_class_is_assignable_from*/
644 if (!mono_class_is_assignable_from_slow (ctr, paramClass))
645 return FALSE;
648 return TRUE;
652 * mono_generic_param_is_constraint_compatible:
654 * \returns TRUE if \p candidate is constraint compatible with \p target.
656 * This means that \p candidate constraints are a super set of \p target constaints
658 static gboolean
659 mono_generic_param_is_constraint_compatible (VerifyContext *ctx, MonoGenericParam *target, MonoGenericParam *candidate, MonoClass *candidate_param_class, MonoGenericContext *context)
661 MonoGenericParamInfo *tinfo = mono_generic_param_info (target);
662 MonoGenericParamInfo *cinfo = mono_generic_param_info (candidate);
663 MonoClass **candidate_class;
664 gboolean class_constraint_satisfied = FALSE;
665 gboolean valuetype_constraint_satisfied = FALSE;
667 int tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
668 int cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
670 if (cinfo->constraints) {
671 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
672 MonoClass *cc;
673 MonoType *inflated = verifier_inflate_type (ctx, m_class_get_byval_arg (*candidate_class), ctx->generic_context);
674 if (!inflated)
675 return FALSE;
676 cc = mono_class_from_mono_type (inflated);
677 mono_metadata_free_type (inflated);
679 if (mono_type_is_reference (m_class_get_byval_arg (cc)) && !MONO_CLASS_IS_INTERFACE (cc))
680 class_constraint_satisfied = TRUE;
681 else if (!mono_type_is_reference (m_class_get_byval_arg (cc)) && !MONO_CLASS_IS_INTERFACE (cc))
682 valuetype_constraint_satisfied = TRUE;
685 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
686 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
688 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
689 return FALSE;
690 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
691 return FALSE;
692 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
693 valuetype_constraint_satisfied)) {
694 return FALSE;
698 if (tinfo->constraints) {
699 MonoClass **target_class;
700 for (target_class = tinfo->constraints; *target_class; ++target_class) {
701 MonoClass *tc;
702 MonoType *inflated = verifier_inflate_type (ctx, m_class_get_byval_arg (*target_class), context);
703 if (!inflated)
704 return FALSE;
705 tc = mono_class_from_mono_type (inflated);
706 mono_metadata_free_type (inflated);
709 * A constraint from @target might inflate into @candidate itself and in that case we don't need
710 * check it's constraints since it satisfy the constraint by itself.
712 if (mono_metadata_type_equal (m_class_get_byval_arg (tc), m_class_get_byval_arg (candidate_param_class)))
713 continue;
715 if (!cinfo->constraints)
716 return FALSE;
718 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
719 MonoClass *cc;
720 inflated = verifier_inflate_type (ctx, m_class_get_byval_arg (*candidate_class), ctx->generic_context);
721 if (!inflated)
722 return FALSE;
723 cc = mono_class_from_mono_type (inflated);
724 mono_metadata_free_type (inflated);
726 if (verifier_class_is_assignable_from (tc, cc))
727 break;
730 * This happens when we have the following:
732 * Bar<K> where K : IFace
733 * Foo<T, U> where T : U where U : IFace
734 * ...
735 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
738 if (mono_type_is_generic_argument (m_class_get_byval_arg (cc))) {
739 MonoGenericParam *other_candidate = verifier_get_generic_param_from_type (ctx, m_class_get_byval_arg (cc));
741 if (mono_generic_param_is_constraint_compatible (ctx, target, other_candidate, cc, context)) {
742 break;
746 if (!*candidate_class)
747 return FALSE;
750 return TRUE;
753 static MonoGenericParam*
754 verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type)
756 MonoGenericContainer *gc;
757 MonoMethod *method = ctx->method;
758 int num;
760 num = mono_type_get_generic_param_num (type);
762 if (type->type == MONO_TYPE_VAR) {
763 MonoClass *gtd = method->klass;
764 if (mono_class_is_ginst (gtd))
765 gtd = mono_class_get_generic_class (gtd)->container_class;
766 gc = mono_class_try_get_generic_container (gtd);
767 } else { //MVAR
768 MonoMethod *gmd = method;
769 if (method->is_inflated)
770 gmd = ((MonoMethodInflated*)method)->declaring;
771 gc = mono_method_get_generic_container (gmd);
773 if (!gc)
774 return NULL;
775 return mono_generic_container_get_param (gc, num);
781 * Verify if @type is valid for the given @ctx verification context.
782 * this function checks for VAR and MVAR types that are invalid under the current verifier,
783 * This means that it either
785 static gboolean
786 is_valid_type_in_context (VerifyContext *ctx, MonoType *type)
788 return mono_type_is_valid_type_in_context (type, ctx->generic_context);
791 static gboolean
792 is_valid_generic_instantiation_in_context (VerifyContext *ctx, MonoGenericInst *ginst, gboolean check_gtd)
794 int i;
795 for (i = 0; i < ginst->type_argc; ++i) {
796 MonoType *type = ginst->type_argv [i];
798 if (!mono_type_is_valid_type_in_context_full (type, ctx->generic_context, TRUE))
799 return FALSE;
801 return TRUE;
804 static gboolean
805 generic_arguments_respect_constraints (VerifyContext *ctx, MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
807 int i;
808 for (i = 0; i < ginst->type_argc; ++i) {
809 MonoType *type = ginst->type_argv [i];
810 MonoGenericParam *target = mono_generic_container_get_param (gc, i);
811 MonoGenericParam *candidate;
812 MonoClass *candidate_class;
814 if (!mono_type_is_generic_argument (type))
815 continue;
817 if (!is_valid_type_in_context (ctx, type))
818 return FALSE;
820 candidate = verifier_get_generic_param_from_type (ctx, type);
821 candidate_class = mono_class_from_mono_type (type);
823 if (!mono_generic_param_is_constraint_compatible (ctx, target, candidate, candidate_class, context))
824 return FALSE;
826 return TRUE;
829 static gboolean
830 mono_method_repect_method_constraints (VerifyContext *ctx, MonoMethod *method)
832 MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
833 MonoGenericInst *ginst = gmethod->context.method_inst;
834 MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
835 return !gc || generic_arguments_respect_constraints (ctx, gc, &gmethod->context, ginst);
838 static gboolean
839 mono_class_repect_method_constraints (VerifyContext *ctx, MonoClass *klass)
841 MonoGenericClass *gklass = mono_class_get_generic_class (klass);
842 MonoGenericInst *ginst = gklass->context.class_inst;
843 MonoGenericContainer *gc = mono_class_get_generic_container (gklass->container_class);
844 return !gc || generic_arguments_respect_constraints (ctx, gc, &gklass->context, ginst);
847 static gboolean
848 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method)
850 MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
851 MonoGenericInst *ginst = gmethod->context.method_inst;
852 MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
853 if (!gc) /*non-generic inflated method - it's part of a generic type */
854 return TRUE;
855 if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst, TRUE))
856 return FALSE;
857 return is_valid_generic_instantiation (gc, &gmethod->context, ginst);
861 static gboolean
862 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass)
864 MonoGenericClass *gklass = mono_class_get_generic_class (klass);
865 MonoGenericInst *ginst = gklass->context.class_inst;
866 MonoGenericContainer *gc = mono_class_get_generic_container (gklass->container_class);
867 if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst, TRUE))
868 return FALSE;
869 return is_valid_generic_instantiation (gc, &gklass->context, ginst);
872 static gboolean
873 mono_type_is_valid_in_context (VerifyContext *ctx, MonoType *type)
875 MonoClass *klass;
877 if (type == NULL) {
878 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid null type at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
879 return FALSE;
882 if (!is_valid_type_in_context (ctx, type)) {
883 char *str = mono_type_full_name (type);
884 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type (%s%s) (argument out of range or %s is not generic) at 0x%04x",
885 str [0] == '!' ? "" : type->type == MONO_TYPE_VAR ? "!" : "!!",
886 str,
887 type->type == MONO_TYPE_VAR ? "class" : "method",
888 ctx->ip_offset),
889 MONO_EXCEPTION_BAD_IMAGE);
890 g_free (str);
891 return FALSE;
894 klass = mono_class_from_mono_type (type);
895 mono_class_init (klass);
896 if (mono_class_has_failure (klass)) {
897 if (mono_class_is_ginst (klass) && !mono_class_is_valid_generic_instantiation (NULL, klass))
898 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);
899 else
900 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);
901 return FALSE;
904 if (mono_class_is_ginst (klass) && mono_class_has_failure (mono_class_get_generic_class (klass)->container_class)) {
905 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);
906 return FALSE;
909 if (!mono_class_is_ginst (klass))
910 return TRUE;
912 if (!mono_class_is_valid_generic_instantiation (ctx, klass)) {
913 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);
914 return FALSE;
917 if (!mono_class_repect_method_constraints (ctx, klass)) {
918 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);
919 return FALSE;
922 return TRUE;
925 static verify_result_t
926 mono_method_is_valid_in_context (VerifyContext *ctx, MonoMethod *method)
928 if (!mono_type_is_valid_in_context (ctx, m_class_get_byval_arg (method->klass)))
929 return RESULT_INVALID;
931 if (!method->is_inflated)
932 return RESULT_VALID;
934 if (!mono_method_is_valid_generic_instantiation (ctx, method)) {
935 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);
936 return RESULT_INVALID;
939 if (!mono_method_repect_method_constraints (ctx, method)) {
940 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));
941 return RESULT_UNVERIFIABLE;
943 return RESULT_VALID;
947 static MonoClassField*
948 verifier_load_field (VerifyContext *ctx, int token, MonoClass **out_klass, const char *opcode) {
949 ERROR_DECL (error);
950 MonoClassField *field;
951 MonoClass *klass = NULL;
953 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
954 field = (MonoClassField *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
955 klass = field ? field->parent : NULL;
956 } else {
957 if (!IS_FIELD_DEF_OR_REF (token) || !token_bounds_check (ctx->image, token)) {
958 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);
959 return NULL;
962 field = mono_field_from_token_checked (ctx->image, token, &klass, ctx->generic_context, error);
963 mono_error_cleanup (error); /*FIXME don't swallow the error */
966 if (!field || !field->parent || !klass) {
967 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);
968 return NULL;
971 if (!mono_type_is_valid_in_context (ctx, m_class_get_byval_arg (klass)))
972 return NULL;
974 if (mono_field_get_flags (field) & FIELD_ATTRIBUTE_LITERAL) {
975 char *type_name = mono_type_get_full_name (field->parent);
976 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot reference literal field %s::%s at 0x%04x", type_name, field->name, ctx->ip_offset));
977 g_free (type_name);
978 return NULL;
981 *out_klass = klass;
982 return field;
985 static MonoMethod*
986 verifier_load_method (VerifyContext *ctx, int token, const char *opcode) {
987 MonoMethod* method;
990 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
991 method = (MonoMethod *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
992 } else {
993 ERROR_DECL (error);
994 if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
995 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);
996 return NULL;
999 method = mono_get_method_checked (ctx->image, token, NULL, ctx->generic_context, error);
1000 mono_error_cleanup (error); /* FIXME don't swallow this error */
1003 if (!method) {
1004 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);
1005 return NULL;
1008 if (mono_method_is_valid_in_context (ctx, method) == RESULT_INVALID)
1009 return NULL;
1011 return method;
1014 static MonoType*
1015 verifier_load_type (VerifyContext *ctx, int token, const char *opcode) {
1016 MonoType* type;
1018 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
1019 MonoClass *klass = (MonoClass *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
1020 type = klass ? m_class_get_byval_arg (klass) : NULL;
1021 } else {
1022 ERROR_DECL (error);
1023 if (!IS_TYPE_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
1024 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid type token 0x%08x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
1025 return NULL;
1027 type = mono_type_get_checked (ctx->image, token, ctx->generic_context, error);
1028 mono_error_cleanup (error); /*FIXME don't swallow the error */
1031 if (!type) {
1032 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);
1033 return NULL;
1036 if (!mono_type_is_valid_in_context (ctx, type))
1037 return NULL;
1039 return type;
1043 /* stack_slot_get_type:
1045 * Returns the stack type of @value. This value includes POINTER_MASK.
1047 * Use this function to checks that account for a managed pointer.
1049 static gint32
1050 stack_slot_get_type (ILStackDesc *value)
1052 return value->stype & RAW_TYPE_MASK;
1055 /* stack_slot_get_underlying_type:
1057 * Returns the stack type of @value. This value does not include POINTER_MASK.
1059 * Use this function is cases where the fact that the value could be a managed pointer is
1060 * irrelevant. For example, field load doesn't care about this fact of type on stack.
1062 static gint32
1063 stack_slot_get_underlying_type (ILStackDesc *value)
1065 return value->stype & TYPE_MASK;
1068 /* stack_slot_is_managed_pointer:
1070 * Returns TRUE is @value is a managed pointer.
1072 static gboolean
1073 stack_slot_is_managed_pointer (ILStackDesc *value)
1075 return (value->stype & POINTER_MASK) == POINTER_MASK;
1078 /* stack_slot_is_managed_mutability_pointer:
1080 * Returns TRUE is @value is a managed mutability pointer.
1082 static G_GNUC_UNUSED gboolean
1083 stack_slot_is_managed_mutability_pointer (ILStackDesc *value)
1085 return (value->stype & CMMP_MASK) == CMMP_MASK;
1088 /* stack_slot_is_null_literal:
1090 * Returns TRUE is @value is the null literal.
1092 static gboolean
1093 stack_slot_is_null_literal (ILStackDesc *value)
1095 return (value->stype & NULL_LITERAL_MASK) == NULL_LITERAL_MASK;
1099 /* stack_slot_is_this_pointer:
1101 * Returns TRUE is @value is the this literal
1103 static gboolean
1104 stack_slot_is_this_pointer (ILStackDesc *value)
1106 return (value->stype & THIS_POINTER_MASK) == THIS_POINTER_MASK;
1109 /* stack_slot_is_boxed_value:
1111 * Returns TRUE is @value is a boxed value
1113 static gboolean
1114 stack_slot_is_boxed_value (ILStackDesc *value)
1116 return (value->stype & BOXED_MASK) == BOXED_MASK;
1119 /* stack_slot_is_safe_byref:
1121 * Returns TRUE is @value is a safe byref
1123 static gboolean
1124 stack_slot_is_safe_byref (ILStackDesc *value)
1126 return (value->stype & SAFE_BYREF_MASK) == SAFE_BYREF_MASK;
1129 static const char *
1130 stack_slot_get_name (ILStackDesc *value)
1132 return type_names [value->stype & TYPE_MASK];
1135 enum {
1136 SAFE_BYREF_LOCAL = 1,
1137 UNSAFE_BYREF_LOCAL = 2
1139 static gboolean
1140 local_is_safe_byref (VerifyContext *ctx, unsigned int arg)
1142 return ctx->locals_verification_state [arg] == SAFE_BYREF_LOCAL;
1145 static gboolean
1146 local_is_unsafe_byref (VerifyContext *ctx, unsigned int arg)
1148 return ctx->locals_verification_state [arg] == UNSAFE_BYREF_LOCAL;
1151 #define APPEND_WITH_PREDICATE(PRED,NAME) do {\
1152 if (PRED (value)) { \
1153 if (!first) \
1154 g_string_append (str, ", "); \
1155 g_string_append (str, NAME); \
1156 first = FALSE; \
1157 } } while (0)
1159 static char*
1160 stack_slot_stack_type_full_name (ILStackDesc *value)
1162 GString *str = g_string_new ("");
1163 char *result;
1164 gboolean has_pred = FALSE, first = TRUE;
1166 if ((value->stype & TYPE_MASK) != value->stype) {
1167 g_string_append(str, "[");
1168 APPEND_WITH_PREDICATE (stack_slot_is_this_pointer, "this");
1169 APPEND_WITH_PREDICATE (stack_slot_is_boxed_value, "boxed");
1170 APPEND_WITH_PREDICATE (stack_slot_is_null_literal, "null");
1171 APPEND_WITH_PREDICATE (stack_slot_is_managed_mutability_pointer, "cmmp");
1172 APPEND_WITH_PREDICATE (stack_slot_is_managed_pointer, "mp");
1173 APPEND_WITH_PREDICATE (stack_slot_is_safe_byref, "safe-byref");
1174 has_pred = TRUE;
1177 if (mono_type_is_generic_argument (value->type) && !stack_slot_is_boxed_value (value)) {
1178 if (!has_pred)
1179 g_string_append(str, "[");
1180 if (!first)
1181 g_string_append (str, ", ");
1182 g_string_append (str, "unboxed");
1183 has_pred = TRUE;
1186 if (has_pred)
1187 g_string_append(str, "] ");
1189 g_string_append (str, stack_slot_get_name (value));
1190 result = str->str;
1191 g_string_free (str, FALSE);
1192 return result;
1195 static char*
1196 stack_slot_full_name (ILStackDesc *value)
1198 char *type_name = mono_type_full_name (value->type);
1199 char *stack_name = stack_slot_stack_type_full_name (value);
1200 char *res = g_strdup_printf ("%s (%s)", type_name, stack_name);
1201 g_free (type_name);
1202 g_free (stack_name);
1203 return res;
1206 //////////////////////////////////////////////////////////////////
1209 * mono_free_verify_list:
1211 void
1212 mono_free_verify_list (GSList *list)
1214 MonoVerifyInfoExtended *info;
1215 GSList *tmp;
1217 for (tmp = list; tmp; tmp = tmp->next) {
1218 info = (MonoVerifyInfoExtended *)tmp->data;
1219 g_free (info->info.message);
1220 g_free (info);
1222 g_slist_free (list);
1225 #define ADD_ERROR(list,msg) \
1226 do { \
1227 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1228 vinfo->info.status = MONO_VERIFY_ERROR; \
1229 vinfo->info.message = (msg); \
1230 (list) = g_slist_prepend ((list), vinfo); \
1231 } while (0)
1233 #define ADD_WARN(list,code,msg) \
1234 do { \
1235 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1236 vinfo->info.status = (code); \
1237 vinfo->info.message = (msg); \
1238 (list) = g_slist_prepend ((list), vinfo); \
1239 } while (0)
1241 #define ADD_INVALID(list,msg) \
1242 do { \
1243 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1244 vinfo->status = MONO_VERIFY_ERROR; \
1245 vinfo->message = (msg); \
1246 (list) = g_slist_prepend ((list), vinfo); \
1247 /*G_BREAKPOINT ();*/ \
1248 goto invalid_cil; \
1249 } while (0)
1251 #define CHECK_STACK_UNDERFLOW(num) \
1252 do { \
1253 if (cur_stack < (num)) \
1254 ADD_INVALID (list, g_strdup_printf ("Stack underflow at 0x%04x (%d items instead of %d)", ip_offset, cur_stack, (num))); \
1255 } while (0)
1257 #define CHECK_STACK_OVERFLOW() \
1258 do { \
1259 if (cur_stack >= max_stack) \
1260 ADD_INVALID (list, g_strdup_printf ("Maxstack exceeded at 0x%04x", ip_offset)); \
1261 } while (0)
1264 static int
1265 in_any_block (MonoMethodHeader *header, guint offset)
1267 int i;
1268 MonoExceptionClause *clause;
1270 for (i = 0; i < header->num_clauses; ++i) {
1271 clause = &header->clauses [i];
1272 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1273 return 1;
1274 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1275 return 1;
1276 if (MONO_OFFSET_IN_FILTER (clause, offset))
1277 return 1;
1279 return 0;
1283 * in_any_exception_block:
1285 * Returns TRUE is @offset is part of any exception clause (filter, handler, catch, finally or fault).
1287 static gboolean
1288 in_any_exception_block (MonoMethodHeader *header, guint offset)
1290 int i;
1291 MonoExceptionClause *clause;
1293 for (i = 0; i < header->num_clauses; ++i) {
1294 clause = &header->clauses [i];
1295 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1296 return TRUE;
1297 if (MONO_OFFSET_IN_FILTER (clause, offset))
1298 return TRUE;
1300 return FALSE;
1304 * is_valid_branch_instruction:
1306 * Verify if it's valid to perform a branch from @offset to @target.
1307 * This should be used with br and brtrue/false.
1308 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1309 * The major difference from other similiar functions is that branching into a
1310 * finally/fault block is invalid instead of just unverifiable.
1312 static int
1313 is_valid_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1315 int i;
1316 MonoExceptionClause *clause;
1318 for (i = 0; i < header->num_clauses; ++i) {
1319 clause = &header->clauses [i];
1320 /*branching into a finally block is invalid*/
1321 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) &&
1322 !MONO_OFFSET_IN_HANDLER (clause, offset) &&
1323 MONO_OFFSET_IN_HANDLER (clause, target))
1324 return 2;
1326 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1327 return 1;
1328 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1329 return 1;
1330 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1331 return 1;
1333 return 0;
1337 * is_valid_cmp_branch_instruction:
1339 * Verify if it's valid to perform a branch from @offset to @target.
1340 * This should be used with binary comparison branching instruction, like beq, bge and similars.
1341 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1343 * The major differences from other similar functions are that most errors lead to invalid
1344 * code and only branching out of finally, filter or fault clauses is unverifiable.
1346 static int
1347 is_valid_cmp_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1349 int i;
1350 MonoExceptionClause *clause;
1352 for (i = 0; i < header->num_clauses; ++i) {
1353 clause = &header->clauses [i];
1354 /*branching out of a handler or finally*/
1355 if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE &&
1356 MONO_OFFSET_IN_HANDLER (clause, offset) &&
1357 !MONO_OFFSET_IN_HANDLER (clause, target))
1358 return 1;
1360 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1361 return 2;
1362 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1363 return 2;
1364 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1365 return 2;
1367 return 0;
1371 * A leave can't escape a finally block
1373 static int
1374 is_correct_leave (MonoMethodHeader *header, guint offset, guint target)
1376 int i;
1377 MonoExceptionClause *clause;
1379 for (i = 0; i < header->num_clauses; ++i) {
1380 clause = &header->clauses [i];
1381 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY && MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
1382 return 0;
1383 if (MONO_OFFSET_IN_FILTER (clause, offset))
1384 return 0;
1386 return 1;
1390 * A rethrow can't happen outside of a catch handler.
1392 static int
1393 is_correct_rethrow (MonoMethodHeader *header, guint offset)
1395 int i;
1396 MonoExceptionClause *clause;
1398 for (i = 0; i < header->num_clauses; ++i) {
1399 clause = &header->clauses [i];
1400 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1401 return 1;
1403 return 0;
1407 * An endfinally can't happen outside of a finally/fault handler.
1409 static int
1410 is_correct_endfinally (MonoMethodHeader *header, guint offset)
1412 int i;
1413 MonoExceptionClause *clause;
1415 for (i = 0; i < header->num_clauses; ++i) {
1416 clause = &header->clauses [i];
1417 if (MONO_OFFSET_IN_HANDLER (clause, offset) && (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY))
1418 return 1;
1420 return 0;
1425 * An endfilter can only happens inside a filter clause.
1426 * In non-strict mode filter is allowed inside the handler clause too
1428 static MonoExceptionClause *
1429 is_correct_endfilter (VerifyContext *ctx, guint offset)
1431 int i;
1432 MonoExceptionClause *clause;
1434 for (i = 0; i < ctx->header->num_clauses; ++i) {
1435 clause = &ctx->header->clauses [i];
1436 if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER)
1437 continue;
1438 if (MONO_OFFSET_IN_FILTER (clause, offset))
1439 return clause;
1440 if (!IS_STRICT_MODE (ctx) && MONO_OFFSET_IN_HANDLER (clause, offset))
1441 return clause;
1443 return NULL;
1448 * Non-strict endfilter can happens inside a try block or any handler block
1450 static int
1451 is_unverifiable_endfilter (VerifyContext *ctx, guint offset)
1453 int i;
1454 MonoExceptionClause *clause;
1456 for (i = 0; i < ctx->header->num_clauses; ++i) {
1457 clause = &ctx->header->clauses [i];
1458 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1459 return 1;
1461 return 0;
1464 static gboolean
1465 is_valid_bool_arg (ILStackDesc *arg)
1467 if (stack_slot_is_managed_pointer (arg) || stack_slot_is_boxed_value (arg) || stack_slot_is_null_literal (arg))
1468 return TRUE;
1471 switch (stack_slot_get_underlying_type (arg)) {
1472 case TYPE_I4:
1473 case TYPE_I8:
1474 case TYPE_NATIVE_INT:
1475 case TYPE_PTR:
1476 return TRUE;
1477 case TYPE_COMPLEX:
1478 g_assert (arg->type);
1479 switch (arg->type->type) {
1480 case MONO_TYPE_CLASS:
1481 case MONO_TYPE_STRING:
1482 case MONO_TYPE_OBJECT:
1483 case MONO_TYPE_SZARRAY:
1484 case MONO_TYPE_ARRAY:
1485 case MONO_TYPE_FNPTR:
1486 case MONO_TYPE_PTR:
1487 return TRUE;
1488 case MONO_TYPE_GENERICINST:
1489 /*We need to check if the container class
1490 * of the generic type is a valuetype, iow:
1491 * is it a "class Foo<T>" or a "struct Foo<T>"?
1493 return !m_class_is_valuetype (arg->type->data.generic_class->container_class);
1494 default:
1495 return FALSE;
1497 default:
1498 return FALSE;
1503 /*Type manipulation helper*/
1505 /*Returns the byref version of the supplied MonoType*/
1506 static MonoType*
1507 mono_type_get_type_byref (MonoType *type)
1509 if (type->byref)
1510 return type;
1511 return m_class_get_this_arg (mono_class_from_mono_type (type));
1515 /*Returns the byval version of the supplied MonoType*/
1516 static MonoType*
1517 mono_type_get_type_byval (MonoType *type)
1519 if (!type->byref)
1520 return type;
1521 return m_class_get_byval_arg (mono_class_from_mono_type (type));
1524 static MonoType*
1525 mono_type_from_stack_slot (ILStackDesc *slot)
1527 if (stack_slot_is_managed_pointer (slot))
1528 return mono_type_get_type_byref (slot->type);
1529 return slot->type;
1532 /*Stack manipulation code*/
1534 static void
1535 ensure_stack_size (ILCodeDesc *stack, int required)
1537 int new_size = 8;
1538 ILStackDesc *tmp;
1540 if (required < stack->max_size)
1541 return;
1543 /* We don't have to worry about the exponential growth since stack_copy prune unused space */
1544 new_size = MAX (8, MAX (required, stack->max_size * 2));
1546 g_assert (new_size >= stack->size);
1547 g_assert (new_size >= required);
1549 tmp = g_new0 (ILStackDesc, new_size);
1550 _MEM_ALLOC (sizeof (ILStackDesc) * new_size);
1552 if (stack->stack) {
1553 if (stack->size)
1554 memcpy (tmp, stack->stack, stack->size * sizeof (ILStackDesc));
1555 g_free (stack->stack);
1556 _MEM_FREE (sizeof (ILStackDesc) * stack->max_size);
1559 stack->stack = tmp;
1560 stack->max_size = new_size;
1563 static void
1564 stack_init (VerifyContext *ctx, ILCodeDesc *state)
1566 if (state->flags & IL_CODE_FLAG_STACK_INITED)
1567 return;
1568 state->size = state->max_size = 0;
1569 state->flags |= IL_CODE_FLAG_STACK_INITED;
1572 static void
1573 stack_copy (ILCodeDesc *to, ILCodeDesc *from)
1575 ensure_stack_size (to, from->size);
1576 to->size = from->size;
1578 /*stack copy happens at merge points, which have small stacks*/
1579 if (from->size)
1580 memcpy (to->stack, from->stack, sizeof (ILStackDesc) * from->size);
1583 static void
1584 copy_stack_value (ILStackDesc *to, ILStackDesc *from)
1586 to->stype = from->stype;
1587 to->type = from->type;
1588 to->method = from->method;
1591 static int
1592 check_underflow (VerifyContext *ctx, int size)
1594 if (ctx->eval.size < size) {
1595 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack underflow, required %d, but have %d at 0x%04x", size, ctx->eval.size, ctx->ip_offset));
1596 return 0;
1598 return 1;
1601 static int
1602 check_overflow (VerifyContext *ctx)
1604 if (ctx->eval.size >= ctx->max_stack) {
1605 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have stack-depth %d at 0x%04x", ctx->eval.size + 1, ctx->ip_offset));
1606 return 0;
1608 return 1;
1611 /*This reject out PTR, FNPTR and TYPEDBYREF*/
1612 static gboolean
1613 check_unmanaged_pointer (VerifyContext *ctx, ILStackDesc *value)
1615 if (stack_slot_get_type (value) == TYPE_PTR) {
1616 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1617 return 0;
1619 return 1;
1622 /*TODO verify if MONO_TYPE_TYPEDBYREF is not allowed here as well.*/
1623 static gboolean
1624 check_unverifiable_type (VerifyContext *ctx, MonoType *type)
1626 if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
1627 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1628 return 0;
1630 return 1;
1633 static ILStackDesc *
1634 stack_push (VerifyContext *ctx)
1636 g_assert (ctx->eval.size < ctx->max_stack);
1637 g_assert (ctx->eval.size <= ctx->eval.max_size);
1639 ensure_stack_size (&ctx->eval, ctx->eval.size + 1);
1641 return & ctx->eval.stack [ctx->eval.size++];
1644 static ILStackDesc *
1645 stack_push_val (VerifyContext *ctx, int stype, MonoType *type)
1647 ILStackDesc *top = stack_push (ctx);
1648 top->stype = stype;
1649 top->type = type;
1650 return top;
1653 static ILStackDesc *
1654 stack_pop (VerifyContext *ctx)
1656 ILStackDesc *ret;
1657 g_assert (ctx->eval.size > 0);
1658 ret = ctx->eval.stack + --ctx->eval.size;
1659 if ((ret->stype & UNINIT_THIS_MASK) == UNINIT_THIS_MASK)
1660 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Found use of uninitialized 'this ptr' ref at 0x%04x", ctx->ip_offset));
1661 return ret;
1664 /* This function allows to safely pop an unititialized this ptr from
1665 * the eval stack without marking the method as unverifiable.
1667 static ILStackDesc *
1668 stack_pop_safe (VerifyContext *ctx)
1670 g_assert (ctx->eval.size > 0);
1671 return ctx->eval.stack + --ctx->eval.size;
1674 /*Positive number distance from stack top. [0] is stack top, [1] is the one below*/
1675 static ILStackDesc*
1676 stack_peek (VerifyContext *ctx, int distance)
1678 g_assert (ctx->eval.size - distance > 0);
1679 return ctx->eval.stack + (ctx->eval.size - 1 - distance);
1682 static ILStackDesc *
1683 stack_push_stack_val (VerifyContext *ctx, ILStackDesc *value)
1685 ILStackDesc *top = stack_push (ctx);
1686 copy_stack_value (top, value);
1687 return top;
1690 /* Returns the MonoType associated with the token, or NULL if it is invalid.
1692 * A boxable type can be either a reference or value type, but cannot be a byref type or an unmanaged pointer
1693 * */
1694 static MonoType*
1695 get_boxable_mono_type (VerifyContext* ctx, int token, const char *opcode)
1697 MonoType *type;
1698 MonoClass *klass;
1700 if (!(type = verifier_load_type (ctx, token, opcode)))
1701 return NULL;
1703 if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
1704 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type for %s at 0x%04x", opcode, ctx->ip_offset));
1705 return NULL;
1708 if (type->type == MONO_TYPE_VOID) {
1709 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type for %s at 0x%04x", opcode, ctx->ip_offset));
1710 return NULL;
1713 if (type->type == MONO_TYPE_TYPEDBYREF)
1714 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid use of typedbyref for %s at 0x%04x", opcode, ctx->ip_offset));
1716 if (!(klass = mono_class_from_mono_type (type)))
1717 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not retrieve type token for %s at 0x%04x", opcode, ctx->ip_offset));
1719 if (mono_class_is_gtd (klass) && type->type != MONO_TYPE_GENERICINST)
1720 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));
1722 check_unverifiable_type (ctx, type);
1723 return type;
1727 /*operation result tables */
1729 static const unsigned char bin_op_table [TYPE_MAX][TYPE_MAX] = {
1730 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1731 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1732 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1733 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1734 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1735 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1738 static const unsigned char add_table [TYPE_MAX][TYPE_MAX] = {
1739 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1740 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1741 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1742 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1743 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1744 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1747 static const unsigned char sub_table [TYPE_MAX][TYPE_MAX] = {
1748 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1749 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1750 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1751 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1752 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1753 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1756 static const unsigned char int_bin_op_table [TYPE_MAX][TYPE_MAX] = {
1757 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1758 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1759 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1760 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1761 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1762 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1765 static const unsigned char shift_op_table [TYPE_MAX][TYPE_MAX] = {
1766 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1767 {TYPE_I8, TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV},
1768 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, 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},
1771 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1774 static const unsigned char cmp_br_op [TYPE_MAX][TYPE_MAX] = {
1775 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1776 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1777 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1778 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1779 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV},
1780 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1783 static const unsigned char cmp_br_eq_op [TYPE_MAX][TYPE_MAX] = {
1784 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1785 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1786 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV},
1787 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1788 {TYPE_INV, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_I4, TYPE_INV},
1789 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4},
1792 static const unsigned char add_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
1793 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1794 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1795 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1796 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1797 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1798 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1801 static const unsigned char sub_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
1802 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1803 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1804 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1805 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1806 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1807 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1810 static const unsigned char bin_ovf_table [TYPE_MAX][TYPE_MAX] = {
1811 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1812 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1813 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1814 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1815 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1816 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1819 #ifdef MONO_VERIFIER_DEBUG
1821 /*debug helpers */
1822 static void
1823 dump_stack_value (ILStackDesc *value)
1825 printf ("[(%x)(%x)", value->type->type, value->stype);
1827 if (stack_slot_is_this_pointer (value))
1828 printf ("[this] ");
1830 if (stack_slot_is_boxed_value (value))
1831 printf ("[boxed] ");
1833 if (stack_slot_is_null_literal (value))
1834 printf ("[null] ");
1836 if (stack_slot_is_managed_mutability_pointer (value))
1837 printf ("Controled Mutability MP: ");
1839 if (stack_slot_is_managed_pointer (value))
1840 printf ("Managed Pointer to: ");
1842 if (stack_slot_is_safe_byref (value))
1843 printf ("Safe ByRef to: ");
1845 switch (stack_slot_get_underlying_type (value)) {
1846 case TYPE_INV:
1847 printf ("invalid type]");
1848 return;
1849 case TYPE_I4:
1850 printf ("int32]");
1851 return;
1852 case TYPE_I8:
1853 printf ("int64]");
1854 return;
1855 case TYPE_NATIVE_INT:
1856 printf ("native int]");
1857 return;
1858 case TYPE_R8:
1859 printf ("float64]");
1860 return;
1861 case TYPE_PTR:
1862 printf ("unmanaged pointer]");
1863 return;
1864 case TYPE_COMPLEX:
1865 switch (value->type->type) {
1866 case MONO_TYPE_CLASS:
1867 case MONO_TYPE_VALUETYPE:
1868 printf ("complex] (%s)", value->type->data.klass->name);
1869 return;
1870 case MONO_TYPE_STRING:
1871 printf ("complex] (string)");
1872 return;
1873 case MONO_TYPE_OBJECT:
1874 printf ("complex] (object)");
1875 return;
1876 case MONO_TYPE_SZARRAY:
1877 printf ("complex] (%s [])", value->type->data.klass->name);
1878 return;
1879 case MONO_TYPE_ARRAY:
1880 printf ("complex] (%s [%d %d %d])",
1881 value->type->data.array->eklass->name,
1882 value->type->data.array->rank,
1883 value->type->data.array->numsizes,
1884 value->type->data.array->numlobounds);
1885 return;
1886 case MONO_TYPE_GENERICINST:
1887 printf ("complex] (inst of %s )", value->type->data.generic_class->container_class->name);
1888 return;
1889 case MONO_TYPE_VAR:
1890 printf ("complex] (type generic param !%d - %s) ", value->type->data.generic_param->num, mono_generic_param_name (value->type->data.generic_param));
1891 return;
1892 case MONO_TYPE_MVAR:
1893 printf ("complex] (method generic param !!%d - %s) ", value->type->data.generic_param->num, mono_generic_param_name (value->type->data.generic_param));
1894 return;
1895 default: {
1896 //should be a boxed value
1897 char * name = mono_type_full_name (value->type);
1898 printf ("complex] %s", name);
1899 g_free (name);
1900 return;
1903 default:
1904 printf ("unknown stack %x type]\n", value->stype);
1905 g_assert_not_reached ();
1909 static void
1910 dump_stack_state (ILCodeDesc *state)
1912 int i;
1914 printf ("(%d) ", state->size);
1915 for (i = 0; i < state->size; ++i)
1916 dump_stack_value (state->stack + i);
1917 printf ("\n");
1919 #endif
1922 * is_array_type_compatible:
1924 * Returns TRUE if candidate array type can be assigned to target.
1926 * Both parameters MUST be of type MONO_TYPE_ARRAY (target->type == MONO_TYPE_ARRAY)
1928 static gboolean
1929 is_array_type_compatible (MonoType *target, MonoType *candidate)
1931 MonoArrayType *left = target->data.array;
1932 MonoArrayType *right = candidate->data.array;
1934 g_assert (target->type == MONO_TYPE_ARRAY);
1935 g_assert (candidate->type == MONO_TYPE_ARRAY);
1937 if (left->rank != right->rank)
1938 return FALSE;
1940 return verifier_class_is_assignable_from (left->eklass, right->eklass);
1943 static int
1944 get_stack_type (MonoType *type)
1946 int mask = 0;
1947 int type_kind = type->type;
1948 if (type->byref)
1949 mask = POINTER_MASK;
1950 /*TODO handle CMMP_MASK */
1952 handle_enum:
1953 switch (type_kind) {
1954 case MONO_TYPE_I1:
1955 case MONO_TYPE_U1:
1956 case MONO_TYPE_BOOLEAN:
1957 case MONO_TYPE_I2:
1958 case MONO_TYPE_U2:
1959 case MONO_TYPE_CHAR:
1960 case MONO_TYPE_I4:
1961 case MONO_TYPE_U4:
1962 return TYPE_I4 | mask;
1964 case MONO_TYPE_I:
1965 case MONO_TYPE_U:
1966 return TYPE_NATIVE_INT | mask;
1968 /* FIXME: the spec says that you cannot have a pointer to method pointer, do we need to check this here? */
1969 case MONO_TYPE_FNPTR:
1970 case MONO_TYPE_PTR:
1971 case MONO_TYPE_TYPEDBYREF:
1972 return TYPE_PTR | mask;
1974 case MONO_TYPE_VAR:
1975 case MONO_TYPE_MVAR:
1977 case MONO_TYPE_CLASS:
1978 case MONO_TYPE_STRING:
1979 case MONO_TYPE_OBJECT:
1980 case MONO_TYPE_SZARRAY:
1981 case MONO_TYPE_ARRAY:
1982 return TYPE_COMPLEX | mask;
1984 case MONO_TYPE_I8:
1985 case MONO_TYPE_U8:
1986 return TYPE_I8 | mask;
1988 case MONO_TYPE_R4:
1989 case MONO_TYPE_R8:
1990 return TYPE_R8 | mask;
1992 case MONO_TYPE_GENERICINST:
1993 case MONO_TYPE_VALUETYPE:
1994 if (mono_type_is_enum_type (type)) {
1995 type = mono_type_get_underlying_type_any (type);
1996 if (!type)
1997 return FALSE;
1998 type_kind = type->type;
1999 goto handle_enum;
2000 } else {
2001 return TYPE_COMPLEX | mask;
2004 default:
2005 return TYPE_INV;
2009 /* convert MonoType to ILStackDesc format (stype) */
2010 static gboolean
2011 set_stack_value (VerifyContext *ctx, ILStackDesc *stack, MonoType *type, int take_addr)
2013 int mask = 0;
2014 int type_kind = type->type;
2016 if (type->byref || take_addr)
2017 mask = POINTER_MASK;
2018 /* TODO handle CMMP_MASK */
2020 handle_enum:
2021 stack->type = type;
2023 switch (type_kind) {
2024 case MONO_TYPE_I1:
2025 case MONO_TYPE_U1:
2026 case MONO_TYPE_BOOLEAN:
2027 case MONO_TYPE_I2:
2028 case MONO_TYPE_U2:
2029 case MONO_TYPE_CHAR:
2030 case MONO_TYPE_I4:
2031 case MONO_TYPE_U4:
2032 stack->stype = TYPE_I4 | mask;
2033 break;
2034 case MONO_TYPE_I:
2035 case MONO_TYPE_U:
2036 stack->stype = TYPE_NATIVE_INT | mask;
2037 break;
2039 /*FIXME: Do we need to check if it's a pointer to the method pointer? The spec says it' illegal to have that.*/
2040 case MONO_TYPE_FNPTR:
2041 case MONO_TYPE_PTR:
2042 case MONO_TYPE_TYPEDBYREF:
2043 stack->stype = TYPE_PTR | mask;
2044 break;
2046 case MONO_TYPE_CLASS:
2047 case MONO_TYPE_STRING:
2048 case MONO_TYPE_OBJECT:
2049 case MONO_TYPE_SZARRAY:
2050 case MONO_TYPE_ARRAY:
2052 case MONO_TYPE_VAR:
2053 case MONO_TYPE_MVAR:
2054 stack->stype = TYPE_COMPLEX | mask;
2055 break;
2057 case MONO_TYPE_I8:
2058 case MONO_TYPE_U8:
2059 stack->stype = TYPE_I8 | mask;
2060 break;
2061 case MONO_TYPE_R4:
2062 case MONO_TYPE_R8:
2063 stack->stype = TYPE_R8 | mask;
2064 break;
2065 case MONO_TYPE_GENERICINST:
2066 case MONO_TYPE_VALUETYPE:
2067 if (mono_type_is_enum_type (type)) {
2068 MonoType *utype = mono_type_get_underlying_type_any (type);
2069 if (!utype) {
2070 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not resolve underlying type of %x at %d", type->type, ctx->ip_offset));
2071 return FALSE;
2073 type = utype;
2074 type_kind = type->type;
2075 goto handle_enum;
2076 } else {
2077 stack->stype = TYPE_COMPLEX | mask;
2078 break;
2080 default:
2081 VERIFIER_DEBUG ( printf ("unknown type 0x%02x in eval stack type\n", type->type); );
2082 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Illegal value set on stack 0x%02x at %d", type->type, ctx->ip_offset));
2083 return FALSE;
2085 return TRUE;
2089 * init_stack_with_value_at_exception_boundary:
2091 * Initialize the stack and push a given type.
2092 * The instruction is marked as been on the exception boundary.
2094 static void
2095 init_stack_with_value_at_exception_boundary (VerifyContext *ctx, ILCodeDesc *code, MonoClass *klass)
2097 ERROR_DECL (error);
2098 MonoType *type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (klass), ctx->generic_context, error);
2100 if (!mono_error_ok (error)) {
2101 char *name = mono_type_get_full_name (klass);
2102 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid class %s used for exception", name));
2103 g_free (name);
2104 mono_error_cleanup (error);
2105 return;
2108 if (!ctx->max_stack) {
2109 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack overflow at 0x%04x", ctx->ip_offset));
2110 return;
2113 stack_init (ctx, code);
2114 ensure_stack_size (code, 1);
2115 set_stack_value (ctx, code->stack, type, FALSE);
2116 ctx->exception_types = g_slist_prepend (ctx->exception_types, type);
2117 code->size = 1;
2118 code->flags |= IL_CODE_FLAG_WAS_TARGET;
2119 if (mono_type_is_generic_argument (type))
2120 code->stack->stype |= BOXED_MASK;
2122 /* Class lazy loading functions */
2123 static GENERATE_GET_CLASS_WITH_CACHE (ienumerable, "System.Collections.Generic", "IEnumerable`1")
2124 static GENERATE_GET_CLASS_WITH_CACHE (icollection, "System.Collections.Generic", "ICollection`1")
2125 static GENERATE_GET_CLASS_WITH_CACHE (ireadonly_list, "System.Collections.Generic", "IReadOnlyList`1")
2126 static GENERATE_GET_CLASS_WITH_CACHE (ireadonly_collection, "System.Collections.Generic", "IReadOnlyCollection`1")
2129 static MonoClass*
2130 get_ienumerable_class (void)
2132 return mono_class_get_ienumerable_class ();
2135 static MonoClass*
2136 get_icollection_class (void)
2138 return mono_class_get_icollection_class ();
2141 static MonoClass*
2142 get_ireadonlylist_class (void)
2144 return mono_class_get_ireadonly_list_class ();
2147 static MonoClass*
2148 get_ireadonlycollection_class (void)
2150 return mono_class_get_ireadonly_collection_class ();
2153 static MonoClass*
2154 inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
2156 MonoType *args [1];
2157 args [0] = m_class_get_byval_arg (arg0);
2159 return mono_class_bind_generic_parameters (gtype, 1, args, FALSE);
2162 static gboolean
2163 verifier_inflate_and_check_compat (MonoClass *target, MonoClass *gtd, MonoClass *arg)
2165 MonoClass *tmp;
2166 if (!(tmp = inflate_class_one_arg (gtd, arg)))
2167 return FALSE;
2168 if (mono_class_is_variant_compatible (target, tmp, TRUE))
2169 return TRUE;
2170 return FALSE;
2173 static gboolean
2174 verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate)
2176 MonoClass *iface_gtd;
2178 if (target == candidate)
2179 return TRUE;
2181 if (mono_class_has_variant_generic_params (target)) {
2182 if (MONO_CLASS_IS_INTERFACE (target)) {
2183 if (MONO_CLASS_IS_INTERFACE (candidate) && mono_class_is_variant_compatible (target, candidate, TRUE))
2184 return TRUE;
2186 if (m_class_get_rank (candidate) == 1) {
2187 MonoClass *candidate_element_class = m_class_get_element_class (candidate);
2188 if (verifier_inflate_and_check_compat (target, mono_defaults.generic_ilist_class, candidate_element_class))
2189 return TRUE;
2190 if (verifier_inflate_and_check_compat (target, get_icollection_class (), candidate_element_class))
2191 return TRUE;
2192 if (verifier_inflate_and_check_compat (target, get_ienumerable_class (), candidate_element_class))
2193 return TRUE;
2194 if (verifier_inflate_and_check_compat (target, get_ireadonlylist_class (), candidate_element_class))
2195 return TRUE;
2196 if (verifier_inflate_and_check_compat (target, get_ireadonlycollection_class (), candidate_element_class))
2197 return TRUE;
2198 } else {
2199 ERROR_DECL (error);
2200 int i;
2201 while (candidate && candidate != mono_defaults.object_class) {
2202 mono_class_setup_interfaces (candidate, error);
2203 if (!mono_error_ok (error)) {
2204 mono_error_cleanup (error);
2205 return FALSE;
2208 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
2209 guint16 candidate_interface_offsets_count = m_class_get_interface_offsets_count (candidate);
2210 MonoClass **candidate_interfaces_packed = m_class_get_interfaces_packed (candidate);
2211 for (i = 0; i < candidate_interface_offsets_count; ++i) {
2212 MonoClass *iface = candidate_interfaces_packed [i];
2213 if (mono_class_is_variant_compatible (target, iface, TRUE))
2214 return TRUE;
2217 guint16 candidate_interface_count = m_class_get_interface_count (candidate);
2218 MonoClass **candidate_interfaces = m_class_get_interfaces (candidate);
2219 for (i = 0; i < candidate_interface_count; ++i) {
2220 MonoClass *iface = candidate_interfaces [i];
2221 if (mono_class_is_variant_compatible (target, iface, TRUE))
2222 return TRUE;
2224 candidate = m_class_get_parent (candidate);
2227 } else if (m_class_is_delegate (target)) {
2228 if (mono_class_is_variant_compatible (target, candidate, TRUE))
2229 return TRUE;
2231 return FALSE;
2234 if (mono_class_is_assignable_from (target, candidate))
2235 return TRUE;
2237 if (!MONO_CLASS_IS_INTERFACE (target) || !mono_class_is_ginst (target) || m_class_get_rank (candidate) != 1)
2238 return FALSE;
2240 iface_gtd = mono_class_get_generic_class (target)->container_class;
2241 if (iface_gtd != mono_defaults.generic_ilist_class && iface_gtd != get_icollection_class () && iface_gtd != get_ienumerable_class ())
2242 return FALSE;
2244 target = mono_class_from_mono_type (mono_class_get_generic_class (target)->context.class_inst->type_argv [0]);
2245 candidate = m_class_get_element_class (candidate);
2247 return TRUE;
2250 /*Verify if type 'candidate' can be stored in type 'target'.
2252 * If strict, check for the underlying type and not the verification stack types
2254 static gboolean
2255 verify_type_compatibility_full (VerifyContext *ctx, MonoType *target, MonoType *candidate, gboolean strict)
2257 #define IS_ONE_OF3(T, A, B, C) (T == A || T == B || T == C)
2258 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
2260 MonoType *original_candidate = candidate;
2261 VERIFIER_DEBUG ( printf ("checking type compatibility %s x %s strict %d\n", mono_type_full_name (target), mono_type_full_name (candidate), strict); );
2263 /*only one is byref */
2264 if (candidate->byref ^ target->byref) {
2265 /* converting from native int to byref*/
2266 if (get_stack_type (candidate) == TYPE_NATIVE_INT && target->byref) {
2267 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("using byref native int at 0x%04x", ctx->ip_offset));
2268 return TRUE;
2270 return FALSE;
2272 strict |= target->byref;
2273 /*From now on we don't care about byref anymore, so it's ok to discard it here*/
2274 candidate = mono_type_get_underlying_type_any (candidate);
2276 handle_enum:
2277 switch (target->type) {
2278 case MONO_TYPE_VOID:
2279 return candidate->type == MONO_TYPE_VOID;
2280 case MONO_TYPE_I1:
2281 case MONO_TYPE_U1:
2282 case MONO_TYPE_BOOLEAN:
2283 if (strict)
2284 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I1, MONO_TYPE_U1, MONO_TYPE_BOOLEAN);
2285 case MONO_TYPE_I2:
2286 case MONO_TYPE_U2:
2287 case MONO_TYPE_CHAR:
2288 if (strict)
2289 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I2, MONO_TYPE_U2, MONO_TYPE_CHAR);
2290 case MONO_TYPE_I4:
2291 case MONO_TYPE_U4: {
2292 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2293 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2294 if (strict)
2295 return is_native_int || is_int4;
2296 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2299 case MONO_TYPE_I8:
2300 case MONO_TYPE_U8:
2301 return IS_ONE_OF2 (candidate->type, MONO_TYPE_I8, MONO_TYPE_U8);
2303 case MONO_TYPE_R4:
2304 case MONO_TYPE_R8:
2305 if (strict)
2306 return candidate->type == target->type;
2307 return IS_ONE_OF2 (candidate->type, MONO_TYPE_R4, MONO_TYPE_R8);
2309 case MONO_TYPE_I:
2310 case MONO_TYPE_U: {
2311 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2312 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2313 if (strict)
2314 return is_native_int || is_int4;
2315 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2318 case MONO_TYPE_PTR:
2319 if (candidate->type != MONO_TYPE_PTR)
2320 return FALSE;
2321 /* check the underlying type */
2322 return verify_type_compatibility_full (ctx, target->data.type, candidate->data.type, TRUE);
2324 case MONO_TYPE_FNPTR: {
2325 MonoMethodSignature *left, *right;
2326 if (candidate->type != MONO_TYPE_FNPTR)
2327 return FALSE;
2329 left = mono_type_get_signature (target);
2330 right = mono_type_get_signature (candidate);
2331 return mono_metadata_signature_equal (left, right) && left->call_convention == right->call_convention;
2334 case MONO_TYPE_GENERICINST: {
2335 MonoClass *target_klass;
2336 MonoClass *candidate_klass;
2337 if (mono_type_is_enum_type (target)) {
2338 target = mono_type_get_underlying_type_any (target);
2339 if (!target)
2340 return FALSE;
2341 goto handle_enum;
2344 * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
2345 * to take boxing status into account.
2347 if (mono_type_is_generic_argument (original_candidate))
2348 return FALSE;
2350 target_klass = mono_class_from_mono_type (target);
2351 candidate_klass = mono_class_from_mono_type (candidate);
2352 if (mono_class_is_nullable (target_klass)) {
2353 if (!mono_class_is_nullable (candidate_klass))
2354 return FALSE;
2355 return target_klass == candidate_klass;
2357 return verifier_class_is_assignable_from (target_klass, candidate_klass);
2360 case MONO_TYPE_STRING:
2361 return candidate->type == MONO_TYPE_STRING;
2363 case MONO_TYPE_CLASS:
2365 * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
2366 * to take boxing status into account.
2368 if (mono_type_is_generic_argument (original_candidate))
2369 return FALSE;
2371 if (candidate->type == MONO_TYPE_VALUETYPE)
2372 return FALSE;
2374 /* If candidate is an enum it should return true for System.Enum and supertypes.
2375 * That's why here we use the original type and not the underlying type.
2377 return verifier_class_is_assignable_from (target->data.klass, mono_class_from_mono_type (original_candidate));
2379 case MONO_TYPE_OBJECT:
2380 return MONO_TYPE_IS_REFERENCE (candidate);
2382 case MONO_TYPE_SZARRAY: {
2383 MonoClass *left;
2384 MonoClass *right;
2385 if (candidate->type != MONO_TYPE_SZARRAY)
2386 return FALSE;
2388 left = mono_class_from_mono_type (target);
2389 right = mono_class_from_mono_type (candidate);
2391 return verifier_class_is_assignable_from (left, right);
2394 case MONO_TYPE_ARRAY:
2395 if (candidate->type != MONO_TYPE_ARRAY)
2396 return FALSE;
2397 return is_array_type_compatible (target, candidate);
2399 case MONO_TYPE_TYPEDBYREF:
2400 return candidate->type == MONO_TYPE_TYPEDBYREF;
2402 case MONO_TYPE_VALUETYPE: {
2403 MonoClass *target_klass;
2404 MonoClass *candidate_klass;
2406 if (candidate->type == MONO_TYPE_CLASS)
2407 return FALSE;
2409 target_klass = mono_class_from_mono_type (target);
2410 candidate_klass = mono_class_from_mono_type (candidate);
2411 if (target_klass == candidate_klass)
2412 return TRUE;
2413 if (mono_type_is_enum_type (target)) {
2414 target = mono_type_get_underlying_type_any (target);
2415 if (!target)
2416 return FALSE;
2417 goto handle_enum;
2419 return FALSE;
2422 case MONO_TYPE_VAR:
2423 if (candidate->type != MONO_TYPE_VAR)
2424 return FALSE;
2425 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2427 case MONO_TYPE_MVAR:
2428 if (candidate->type != MONO_TYPE_MVAR)
2429 return FALSE;
2430 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2432 default:
2433 VERIFIER_DEBUG ( printf ("unknown store type %d\n", target->type); );
2434 g_assert_not_reached ();
2435 return FALSE;
2437 return 1;
2438 #undef IS_ONE_OF3
2439 #undef IS_ONE_OF2
2442 static gboolean
2443 verify_type_compatibility (VerifyContext *ctx, MonoType *target, MonoType *candidate)
2445 return verify_type_compatibility_full (ctx, target, candidate, FALSE);
2449 * Returns the generic param bound to the context been verified.
2452 static MonoGenericParam*
2453 get_generic_param (VerifyContext *ctx, MonoType *param)
2455 guint16 param_num = mono_type_get_generic_param_num (param);
2456 if (param->type == MONO_TYPE_VAR) {
2457 if (!ctx->generic_context->class_inst || ctx->generic_context->class_inst->type_argc <= param_num) {
2458 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic type argument %d", param_num));
2459 return NULL;
2461 return ctx->generic_context->class_inst->type_argv [param_num]->data.generic_param;
2464 /*param must be a MVAR */
2465 if (!ctx->generic_context->method_inst || ctx->generic_context->method_inst->type_argc <= param_num) {
2466 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic method argument %d", param_num));
2467 return NULL;
2469 return ctx->generic_context->method_inst->type_argv [param_num]->data.generic_param;
2473 static gboolean
2474 recursive_boxed_constraint_type_check (VerifyContext *ctx, MonoType *type, MonoClass *constraint_class, int recursion_level)
2476 MonoType *constraint_type = m_class_get_byval_arg (constraint_class);
2477 if (recursion_level <= 0)
2478 return FALSE;
2480 if (verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (constraint_type), FALSE))
2481 return TRUE;
2483 if (mono_type_is_generic_argument (constraint_type)) {
2484 MonoGenericParam *param = get_generic_param (ctx, constraint_type);
2485 MonoClass **klass;
2486 if (!param)
2487 return FALSE;
2488 for (klass = mono_generic_param_info (param)->constraints; klass && *klass; ++klass) {
2489 if (recursive_boxed_constraint_type_check (ctx, type, *klass, recursion_level - 1))
2490 return TRUE;
2493 return FALSE;
2496 /**
2497 * is_compatible_boxed_valuetype:
2499 * Returns: TRUE if @candidate / @stack is a valid boxed valuetype.
2501 * @type The source type. It it tested to be of the proper type.
2502 * @candidate type of the boxed valuetype.
2503 * @stack stack slot of the boxed valuetype, separate from @candidade since one could be changed before calling this function
2504 * @strict if TRUE candidate must be boxed compatible to the target type
2507 static gboolean
2508 is_compatible_boxed_valuetype (VerifyContext *ctx, MonoType *type, MonoType *candidate, ILStackDesc *stack, gboolean strict)
2510 if (!stack_slot_is_boxed_value (stack))
2511 return FALSE;
2512 if (type->byref || candidate->byref)
2513 return FALSE;
2515 if (mono_type_is_generic_argument (candidate)) {
2516 MonoGenericParam *param = get_generic_param (ctx, candidate);
2517 MonoClass **klass;
2518 if (!param)
2519 return FALSE;
2521 for (klass = mono_generic_param_info (param)->constraints; klass && *klass; ++klass) {
2522 /*256 should be enough since there can't be more than 255 generic arguments.*/
2523 if (recursive_boxed_constraint_type_check (ctx, type, *klass, 256))
2524 return TRUE;
2528 if (mono_type_is_generic_argument (type))
2529 return FALSE;
2531 if (!strict)
2532 return TRUE;
2534 return MONO_TYPE_IS_REFERENCE (type) && verifier_class_is_assignable_from (mono_class_from_mono_type (type), mono_class_from_mono_type (candidate));
2537 static int
2538 verify_stack_type_compatibility_full (VerifyContext *ctx, MonoType *type, ILStackDesc *stack, gboolean drop_byref, gboolean valuetype_must_be_boxed)
2540 MonoType *candidate = mono_type_from_stack_slot (stack);
2541 if (MONO_TYPE_IS_REFERENCE (type) && !type->byref && stack_slot_is_null_literal (stack))
2542 return TRUE;
2544 if (is_compatible_boxed_valuetype (ctx, type, candidate, stack, TRUE))
2545 return TRUE;
2547 if (valuetype_must_be_boxed && !stack_slot_is_boxed_value (stack) && !MONO_TYPE_IS_REFERENCE (candidate))
2548 return FALSE;
2550 if (!valuetype_must_be_boxed && stack_slot_is_boxed_value (stack))
2551 return FALSE;
2553 if (drop_byref)
2554 return verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (candidate), FALSE);
2556 /* Handle how Roslyn emit fixed statements by encoding it as byref */
2557 if (type->byref && candidate->byref && (type->type == MONO_TYPE_I) && !mono_type_is_reference (candidate)) {
2558 if (!IS_STRICT_MODE (ctx))
2559 return TRUE;
2562 return verify_type_compatibility_full (ctx, type, candidate, FALSE);
2565 static int
2566 verify_stack_type_compatibility (VerifyContext *ctx, MonoType *type, ILStackDesc *stack)
2568 return verify_stack_type_compatibility_full (ctx, type, stack, FALSE, FALSE);
2571 static gboolean
2572 mono_delegate_type_equal (MonoType *target, MonoType *candidate)
2574 if (candidate->byref ^ target->byref)
2575 return FALSE;
2577 switch (target->type) {
2578 case MONO_TYPE_VOID:
2579 case MONO_TYPE_I1:
2580 case MONO_TYPE_U1:
2581 case MONO_TYPE_BOOLEAN:
2582 case MONO_TYPE_I2:
2583 case MONO_TYPE_U2:
2584 case MONO_TYPE_CHAR:
2585 case MONO_TYPE_I4:
2586 case MONO_TYPE_U4:
2587 case MONO_TYPE_I8:
2588 case MONO_TYPE_U8:
2589 case MONO_TYPE_R4:
2590 case MONO_TYPE_R8:
2591 case MONO_TYPE_I:
2592 case MONO_TYPE_U:
2593 case MONO_TYPE_STRING:
2594 case MONO_TYPE_TYPEDBYREF:
2595 return candidate->type == target->type;
2597 case MONO_TYPE_PTR:
2598 if (candidate->type != MONO_TYPE_PTR)
2599 return FALSE;
2600 return mono_delegate_type_equal (target->data.type, candidate->data.type);
2602 case MONO_TYPE_FNPTR:
2603 if (candidate->type != MONO_TYPE_FNPTR)
2604 return FALSE;
2605 return mono_delegate_signature_equal (mono_type_get_signature (target), mono_type_get_signature (candidate), FALSE);
2607 case MONO_TYPE_GENERICINST: {
2608 MonoClass *target_klass;
2609 MonoClass *candidate_klass;
2610 target_klass = mono_class_from_mono_type (target);
2611 candidate_klass = mono_class_from_mono_type (candidate);
2612 /*FIXME handle nullables and enum*/
2613 return verifier_class_is_assignable_from (target_klass, candidate_klass);
2615 case MONO_TYPE_OBJECT:
2616 return MONO_TYPE_IS_REFERENCE (candidate);
2618 case MONO_TYPE_CLASS:
2619 return verifier_class_is_assignable_from(target->data.klass, mono_class_from_mono_type (candidate));
2621 case MONO_TYPE_SZARRAY:
2622 if (candidate->type != MONO_TYPE_SZARRAY)
2623 return FALSE;
2624 return verifier_class_is_assignable_from (m_class_get_element_class (mono_class_from_mono_type (target)), m_class_get_element_class (mono_class_from_mono_type (candidate)));
2626 case MONO_TYPE_ARRAY:
2627 if (candidate->type != MONO_TYPE_ARRAY)
2628 return FALSE;
2629 return is_array_type_compatible (target, candidate);
2631 case MONO_TYPE_VALUETYPE:
2632 /*FIXME handle nullables and enum*/
2633 return mono_class_from_mono_type (candidate) == mono_class_from_mono_type (target);
2635 case MONO_TYPE_VAR:
2636 return candidate->type == MONO_TYPE_VAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2637 return FALSE;
2639 case MONO_TYPE_MVAR:
2640 return candidate->type == MONO_TYPE_MVAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2641 return FALSE;
2643 default:
2644 VERIFIER_DEBUG ( printf ("Unknown type %d. Implement me!\n", target->type); );
2645 g_assert_not_reached ();
2646 return FALSE;
2650 static gboolean
2651 mono_delegate_param_equal (MonoType *delegate, MonoType *method)
2653 if (mono_metadata_type_equal_full (delegate, method, TRUE))
2654 return TRUE;
2656 return mono_delegate_type_equal (method, delegate);
2659 static gboolean
2660 mono_delegate_ret_equal (MonoType *delegate, MonoType *method)
2662 if (mono_metadata_type_equal_full (delegate, method, TRUE))
2663 return TRUE;
2665 return mono_delegate_type_equal (delegate, method);
2669 * mono_delegate_signature_equal:
2671 * Compare two signatures in the way expected by delegates.
2673 * This function only exists due to the fact that it should ignore the 'has_this' part of the signature.
2675 * FIXME can this function be eliminated and proper metadata functionality be used?
2677 static gboolean
2678 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn)
2680 int i;
2681 int method_offset = is_static_ldftn ? 1 : 0;
2683 if (delegate_sig->param_count + method_offset != method_sig->param_count)
2684 return FALSE;
2686 if (delegate_sig->call_convention != method_sig->call_convention)
2687 return FALSE;
2689 for (i = 0; i < delegate_sig->param_count; i++) {
2690 MonoType *p1 = delegate_sig->params [i];
2691 MonoType *p2 = method_sig->params [i + method_offset];
2693 if (!mono_delegate_param_equal (p1, p2))
2694 return FALSE;
2697 if (!mono_delegate_ret_equal (delegate_sig->ret, method_sig->ret))
2698 return FALSE;
2700 return TRUE;
2703 gboolean
2704 mono_verifier_is_signature_compatible (MonoMethodSignature *target, MonoMethodSignature *candidate)
2706 return mono_delegate_signature_equal (target, candidate, FALSE);
2710 * verify_ldftn_delegate:
2712 * Verify properties of ldftn based delegates.
2714 static void
2715 verify_ldftn_delegate (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2717 MonoMethod *method = funptr->method;
2719 /*ldftn non-final virtuals only allowed if method is not static,
2720 * the object is a this arg (comes from a ldarg.0), and there is no starg.0.
2721 * This rules doesn't apply if the object on stack is a boxed valuetype.
2723 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !mono_class_is_sealed (method->klass) && !stack_slot_is_boxed_value (value)) {
2724 /*A stdarg 0 must not happen, we fail here only in fail fast mode to avoid double error reports*/
2725 if (IS_FAIL_FAST_MODE (ctx) && ctx->has_this_store)
2726 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at 0x%04x", ctx->ip_offset));
2728 /*current method must not be static*/
2729 if (ctx->method->flags & METHOD_ATTRIBUTE_STATIC)
2730 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function at 0x%04x", ctx->ip_offset));
2732 /*value is the this pointer, loaded using ldarg.0 */
2733 if (!stack_slot_is_this_pointer (value))
2734 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));
2736 ctx->code [ctx->ip_offset].flags |= IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL;
2741 * verify_delegate_compatibility:
2743 * Verify delegate creation sequence.
2746 static void
2747 verify_delegate_compatibility (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2749 #define IS_VALID_OPCODE(offset, opcode) (ip [ip_offset - offset] == opcode && (ctx->code [ip_offset - offset].flags & IL_CODE_FLAG_SEEN))
2750 #define IS_LOAD_FUN_PTR(kind) (IS_VALID_OPCODE (6, CEE_PREFIX1) && ip [ip_offset - 5] == kind)
2752 MonoMethod *invoke, *method;
2753 const guint8 *ip = ctx->header->code;
2754 guint32 ip_offset = ctx->ip_offset;
2755 gboolean is_static_ldftn = FALSE, is_first_arg_bound = FALSE;
2757 if (stack_slot_get_type (funptr) != TYPE_PTR || !funptr->method) {
2758 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid function pointer parameter for delegate constructor at 0x%04x", ctx->ip_offset));
2759 return;
2762 invoke = mono_get_delegate_invoke (delegate);
2763 method = funptr->method;
2765 if (!method || !mono_method_signature (method)) {
2766 char *name = mono_type_get_full_name (delegate);
2767 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid method on stack to create delegate %s construction at 0x%04x", name, ctx->ip_offset));
2768 g_free (name);
2769 return;
2772 if (!invoke || !mono_method_signature (invoke)) {
2773 char *name = mono_type_get_full_name (delegate);
2774 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Delegate type %s with bad Invoke method at 0x%04x", name, ctx->ip_offset));
2775 g_free (name);
2776 return;
2779 is_static_ldftn = (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) && method->flags & METHOD_ATTRIBUTE_STATIC;
2781 if (is_static_ldftn)
2782 is_first_arg_bound = mono_method_signature (invoke)->param_count + 1 == mono_method_signature (method)->param_count;
2784 if (!mono_delegate_signature_equal (mono_method_signature (invoke), mono_method_signature (method), is_first_arg_bound)) {
2785 char *fun_sig = mono_signature_get_desc (mono_method_signature (method), FALSE);
2786 char *invoke_sig = mono_signature_get_desc (mono_method_signature (invoke), FALSE);
2787 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));
2788 g_free (fun_sig);
2789 g_free (invoke_sig);
2793 * Delegate code sequences:
2794 * [-6] ldftn token
2795 * newobj ...
2798 * [-7] dup
2799 * [-6] ldvirtftn token
2800 * newobj ...
2802 * ldftn sequence:*/
2803 if (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) {
2804 verify_ldftn_delegate (ctx, delegate, value, funptr);
2805 } else if (ip_offset > 6 && IS_VALID_OPCODE (7, CEE_DUP) && IS_LOAD_FUN_PTR (CEE_LDVIRTFTN)) {
2806 ctx->code [ip_offset - 6].flags |= IL_CODE_DELEGATE_SEQUENCE;
2807 }else {
2808 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid code sequence for delegate creation at 0x%04x", ctx->ip_offset));
2810 ctx->code [ip_offset].flags |= IL_CODE_DELEGATE_SEQUENCE;
2812 //general tests
2813 if (is_first_arg_bound) {
2814 if (mono_method_signature (method)->param_count == 0 || !verify_stack_type_compatibility_full (ctx, mono_method_signature (method)->params [0], value, FALSE, TRUE))
2815 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2816 } else {
2817 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
2818 if (!stack_slot_is_null_literal (value))
2819 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Non-null this args used with static function for delegate creation at 0x%04x", ctx->ip_offset));
2820 } else {
2821 if (!verify_stack_type_compatibility_full (ctx, m_class_get_byval_arg (method->klass), value, FALSE, TRUE) && !stack_slot_is_null_literal (value))
2822 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2826 if (stack_slot_get_type (value) != TYPE_COMPLEX)
2827 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid first parameter for delegate creation at 0x%04x", ctx->ip_offset));
2829 #undef IS_VALID_OPCODE
2830 #undef IS_LOAD_FUN_PTR
2833 static gboolean
2834 is_this_arg_of_struct_instance_method (unsigned int arg, VerifyContext *ctx)
2836 if (arg != 0)
2837 return FALSE;
2838 if (ctx->method->flags & METHOD_ATTRIBUTE_STATIC)
2839 return FALSE;
2840 if (!m_class_is_valuetype (ctx->method->klass))
2841 return FALSE;
2842 return TRUE;
2845 /* implement the opcode checks*/
2846 static void
2847 push_arg (VerifyContext *ctx, unsigned int arg, int take_addr)
2849 ILStackDesc *top;
2851 if (arg >= ctx->max_args) {
2852 if (take_addr)
2853 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2854 else {
2855 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2856 if (check_overflow (ctx)) //FIXME: what sane value could we ever push?
2857 stack_push_val (ctx, TYPE_I4, m_class_get_byval_arg (mono_defaults.int32_class));
2859 } else if (check_overflow (ctx)) {
2860 /*We must let the value be pushed, otherwise we would get an underflow error*/
2861 check_unverifiable_type (ctx, ctx->params [arg]);
2862 if (ctx->params [arg]->byref && take_addr)
2863 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2864 top = stack_push (ctx);
2865 if (!set_stack_value (ctx, top, ctx->params [arg], take_addr))
2866 return;
2868 if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC)) {
2869 if (take_addr)
2870 ctx->has_this_store = TRUE;
2871 else
2872 top->stype |= THIS_POINTER_MASK;
2873 if (mono_method_is_constructor (ctx->method) && !ctx->super_ctor_called && !m_class_is_valuetype (ctx->method->klass))
2874 top->stype |= UNINIT_THIS_MASK;
2876 if (!take_addr && ctx->params [arg]->byref && !is_this_arg_of_struct_instance_method (arg, ctx))
2877 top->stype |= SAFE_BYREF_MASK;
2881 static void
2882 push_local (VerifyContext *ctx, guint32 arg, int take_addr)
2884 if (arg >= ctx->num_locals) {
2885 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local %d", arg + 1));
2886 } else if (check_overflow (ctx)) {
2887 /*We must let the value be pushed, otherwise we would get an underflow error*/
2888 check_unverifiable_type (ctx, ctx->locals [arg]);
2889 if (ctx->locals [arg]->byref && take_addr)
2890 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2892 ILStackDesc *value = stack_push (ctx);
2893 set_stack_value (ctx, value, ctx->locals [arg], take_addr);
2894 if (local_is_safe_byref (ctx, arg))
2895 value->stype |= SAFE_BYREF_MASK;
2899 static void
2900 store_arg (VerifyContext *ctx, guint32 arg)
2902 ILStackDesc *value;
2904 if (arg >= ctx->max_args) {
2905 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", arg + 1, ctx->ip_offset));
2906 if (check_underflow (ctx, 1))
2907 stack_pop (ctx);
2908 return;
2911 if (check_underflow (ctx, 1)) {
2912 value = stack_pop (ctx);
2913 if (!verify_stack_type_compatibility (ctx, ctx->params [arg], value)) {
2914 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in argument store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
2917 if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC))
2918 ctx->has_this_store = 1;
2921 static void
2922 store_local (VerifyContext *ctx, guint32 arg)
2924 ILStackDesc *value;
2925 if (arg >= ctx->num_locals) {
2926 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", arg + 1, ctx->ip_offset));
2927 return;
2930 /*TODO verify definite assigment */
2931 if (!check_underflow (ctx, 1))
2932 return;
2934 value = stack_pop (ctx);
2935 if (ctx->locals [arg]->byref) {
2936 if (stack_slot_is_managed_mutability_pointer (value))
2937 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));
2939 if (local_is_safe_byref (ctx, arg) && !stack_slot_is_safe_byref (value))
2940 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));
2942 if (stack_slot_is_safe_byref (value) && !local_is_unsafe_byref (ctx, arg))
2943 ctx->locals_verification_state [arg] |= SAFE_BYREF_LOCAL;
2945 if (!stack_slot_is_safe_byref (value))
2946 ctx->locals_verification_state [arg] |= UNSAFE_BYREF_LOCAL;
2949 if (!verify_stack_type_compatibility (ctx, ctx->locals [arg], value)) {
2950 char *expected = mono_type_full_name (ctx->locals [arg]);
2951 char *found = stack_slot_full_name (value);
2952 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type '%s' on stack cannot be stored to local %d with type '%s' at 0x%04x",
2953 found,
2954 arg,
2955 expected,
2956 ctx->ip_offset));
2957 g_free (expected);
2958 g_free (found);
2962 /*FIXME add and sub needs special care here*/
2963 static void
2964 do_binop (VerifyContext *ctx, unsigned int opcode, const unsigned char table [TYPE_MAX][TYPE_MAX])
2966 ILStackDesc *a, *b, *top;
2967 int idxa, idxb, complexMerge = 0;
2968 unsigned char res;
2970 if (!check_underflow (ctx, 2))
2971 return;
2972 b = stack_pop (ctx);
2973 a = stack_pop (ctx);
2975 idxa = stack_slot_get_underlying_type (a);
2976 if (stack_slot_is_managed_pointer (a)) {
2977 idxa = TYPE_PTR;
2978 complexMerge = 1;
2981 idxb = stack_slot_get_underlying_type (b);
2982 if (stack_slot_is_managed_pointer (b)) {
2983 idxb = TYPE_PTR;
2984 complexMerge = 2;
2987 --idxa;
2988 --idxb;
2989 res = table [idxa][idxb];
2991 VERIFIER_DEBUG ( printf ("binop res %d\n", res); );
2992 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
2994 top = stack_push (ctx);
2995 if (res == TYPE_INV) {
2996 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)));
2997 copy_stack_value (top, a);
2998 return;
3001 if (res & NON_VERIFIABLE_RESULT) {
3002 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)));
3004 res = res & ~NON_VERIFIABLE_RESULT;
3007 if (complexMerge && res == TYPE_PTR) {
3008 if (complexMerge == 1)
3009 copy_stack_value (top, a);
3010 else if (complexMerge == 2)
3011 copy_stack_value (top, b);
3013 * There is no need to merge the type of two pointers.
3014 * The only valid operation is subtraction, that returns a native
3015 * int as result and can be used with any 2 pointer kinds.
3016 * This is valid acording to Patition III 1.1.4
3018 } else
3019 top->stype = res;
3024 static void
3025 do_boolean_branch_op (VerifyContext *ctx, int delta)
3027 int target = ctx->ip_offset + delta;
3028 ILStackDesc *top;
3030 VERIFIER_DEBUG ( printf ("boolean branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
3032 if (target < 0 || target >= ctx->code_size) {
3033 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Boolean branch target out of code at 0x%04x", ctx->ip_offset));
3034 return;
3037 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
3038 case 1:
3039 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3040 break;
3041 case 2:
3042 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3043 return;
3046 ctx->target = target;
3048 if (!check_underflow (ctx, 1))
3049 return;
3051 top = stack_pop (ctx);
3052 if (!is_valid_bool_arg (top))
3053 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));
3055 check_unmanaged_pointer (ctx, top);
3058 static gboolean
3059 stack_slot_is_complex_type_not_reference_type (ILStackDesc *slot)
3061 return stack_slot_get_type (slot) == TYPE_COMPLEX && !MONO_TYPE_IS_REFERENCE (slot->type) && !stack_slot_is_boxed_value (slot);
3064 static gboolean
3065 stack_slot_is_reference_value (ILStackDesc *slot)
3067 return stack_slot_get_type (slot) == TYPE_COMPLEX && (MONO_TYPE_IS_REFERENCE (slot->type) || stack_slot_is_boxed_value (slot));
3070 static void
3071 do_branch_op (VerifyContext *ctx, signed int delta, const unsigned char table [TYPE_MAX][TYPE_MAX])
3073 ILStackDesc *a, *b;
3074 int idxa, idxb;
3075 unsigned char res;
3076 int target = ctx->ip_offset + delta;
3078 VERIFIER_DEBUG ( printf ("branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
3080 if (target < 0 || target >= ctx->code_size) {
3081 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
3082 return;
3085 switch (is_valid_cmp_branch_instruction (ctx->header, ctx->ip_offset, target)) {
3086 case 1: /*FIXME use constants and not magic numbers.*/
3087 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3088 break;
3089 case 2:
3090 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3091 return;
3094 ctx->target = target;
3096 if (!check_underflow (ctx, 2))
3097 return;
3099 b = stack_pop (ctx);
3100 a = stack_pop (ctx);
3102 idxa = stack_slot_get_underlying_type (a);
3103 if (stack_slot_is_managed_pointer (a))
3104 idxa = TYPE_PTR;
3106 idxb = stack_slot_get_underlying_type (b);
3107 if (stack_slot_is_managed_pointer (b))
3108 idxb = TYPE_PTR;
3110 if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
3111 res = TYPE_INV;
3112 } else {
3113 --idxa;
3114 --idxb;
3115 res = table [idxa][idxb];
3118 VERIFIER_DEBUG ( printf ("branch res %d\n", res); );
3119 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
3121 if (res == TYPE_INV) {
3122 CODE_NOT_VERIFIABLE (ctx,
3123 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));
3124 } else if (res & NON_VERIFIABLE_RESULT) {
3125 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));
3126 res = res & ~NON_VERIFIABLE_RESULT;
3130 static void
3131 do_cmp_op (VerifyContext *ctx, const unsigned char table [TYPE_MAX][TYPE_MAX], guint32 opcode)
3133 ILStackDesc *a, *b;
3134 int idxa, idxb;
3135 unsigned char res;
3137 if (!check_underflow (ctx, 2))
3138 return;
3139 b = stack_pop (ctx);
3140 a = stack_pop (ctx);
3142 if (opcode == CEE_CGT_UN) {
3143 if ((stack_slot_is_reference_value (a) && stack_slot_is_null_literal (b)) ||
3144 (stack_slot_is_reference_value (b) && stack_slot_is_null_literal (a))) {
3145 stack_push_val (ctx, TYPE_I4, m_class_get_byval_arg (mono_defaults.int32_class));
3146 return;
3150 idxa = stack_slot_get_underlying_type (a);
3151 if (stack_slot_is_managed_pointer (a))
3152 idxa = TYPE_PTR;
3154 idxb = stack_slot_get_underlying_type (b);
3155 if (stack_slot_is_managed_pointer (b))
3156 idxb = TYPE_PTR;
3158 if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
3159 res = TYPE_INV;
3160 } else {
3161 --idxa;
3162 --idxb;
3163 res = table [idxa][idxb];
3166 if(res == TYPE_INV) {
3167 char *left_type = stack_slot_full_name (a);
3168 char *right_type = stack_slot_full_name (b);
3169 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));
3170 g_free (left_type);
3171 g_free (right_type);
3172 } else if (res & NON_VERIFIABLE_RESULT) {
3173 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));
3174 res = res & ~NON_VERIFIABLE_RESULT;
3176 stack_push_val (ctx, TYPE_I4, m_class_get_byval_arg (mono_defaults.int32_class));
3179 static void
3180 do_ret (VerifyContext *ctx)
3182 MonoType *ret = ctx->signature->ret;
3183 VERIFIER_DEBUG ( printf ("checking ret\n"); );
3184 if (ret->type != MONO_TYPE_VOID) {
3185 ILStackDesc *top;
3186 if (!check_underflow (ctx, 1))
3187 return;
3189 top = stack_pop(ctx);
3191 if (!verify_stack_type_compatibility (ctx, ctx->signature->ret, top)) {
3192 char *ret_type = mono_type_full_name (ctx->signature->ret);
3193 char *stack_type = stack_slot_full_name (top);
3194 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));
3195 g_free (stack_type);
3196 g_free (ret_type);
3197 return;
3200 if (ret->byref && !stack_slot_is_safe_byref (top))
3201 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));
3203 if (ret->type == MONO_TYPE_TYPEDBYREF || mono_type_is_value_type (ret, "System", "ArgIterator") || mono_type_is_value_type (ret, "System", "RuntimeArgumentHandle"))
3204 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method returns byref, TypedReference, ArgIterator or RuntimeArgumentHandle at 0x%04x", ctx->ip_offset));
3207 if (ctx->eval.size > 0) {
3208 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack not empty (%d) after ret at 0x%04x", ctx->eval.size, ctx->ip_offset));
3210 if (in_any_block (ctx->header, ctx->ip_offset))
3211 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ret cannot escape exception blocks at 0x%04x", ctx->ip_offset));
3215 * 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.
3216 * This is illegal but mono_get_method_full decoded it.
3217 * TODO handle calling .ctor outside one or calling the .ctor for other class but super
3219 static void
3220 do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual_)
3222 ERROR_DECL (error);
3223 int param_count, i;
3224 MonoMethodSignature *sig;
3225 ILStackDesc *value;
3226 MonoMethod *method;
3227 gboolean virt_check_this = FALSE;
3228 gboolean constrained = ctx->prefix_set & PREFIX_CONSTRAINED;
3230 if (!(method = verifier_load_method (ctx, method_token, virtual_ ? "callvirt" : "call")))
3231 return;
3233 if (virtual_) {
3234 CLEAR_PREFIX (ctx, PREFIX_CONSTRAINED);
3236 if (m_class_is_valuetype (method->klass)) // && !constrained ???
3237 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with valuetype method at 0x%04x", ctx->ip_offset));
3239 if ((method->flags & METHOD_ATTRIBUTE_STATIC))
3240 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with static method at 0x%04x", ctx->ip_offset));
3242 } else {
3243 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
3244 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use call with an abstract method at 0x%04x", ctx->ip_offset));
3246 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !mono_class_is_sealed (method->klass)) {
3247 virt_check_this = TRUE;
3248 ctx->code [ctx->ip_offset].flags |= IL_CODE_CALL_NONFINAL_VIRTUAL;
3252 if (!(sig = mono_method_get_signature_checked (method, ctx->image, method_token, ctx->generic_context, error))) {
3253 mono_error_cleanup (error);
3254 sig = mono_method_get_signature_checked (method, ctx->image, method_token, NULL, error);
3257 if (!sig) {
3258 char *name = mono_type_get_full_name (method->klass);
3259 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)));
3260 mono_error_cleanup (error);
3261 g_free (name);
3262 return;
3265 param_count = sig->param_count + sig->hasthis;
3266 if (!check_underflow (ctx, param_count))
3267 return;
3269 gboolean is_safe_byref_call = TRUE;
3271 for (i = sig->param_count - 1; i >= 0; --i) {
3272 VERIFIER_DEBUG ( printf ("verifying argument %d\n", i); );
3273 value = stack_pop (ctx);
3274 if (!verify_stack_type_compatibility (ctx, sig->params[i], value)) {
3275 char *stack_name = stack_slot_full_name (value);
3276 char *sig_name = mono_type_full_name (sig->params [i]);
3277 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));
3278 g_free (stack_name);
3279 g_free (sig_name);
3282 if (stack_slot_is_managed_mutability_pointer (value))
3283 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));
3285 if ((ctx->prefix_set & PREFIX_TAIL) && stack_slot_is_managed_pointer (value)) {
3286 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));
3287 return;
3289 if (stack_slot_is_managed_pointer (value) && !stack_slot_is_safe_byref (value))
3290 is_safe_byref_call = FALSE;
3293 if (sig->hasthis) {
3294 MonoType *type = m_class_get_byval_arg (method->klass);
3295 ILStackDesc copy;
3297 if (mono_method_is_constructor (method) && !m_class_is_valuetype (method->klass)) {
3298 if (IS_STRICT_MODE (ctx) && !mono_method_is_constructor (ctx->method))
3299 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor outside one at 0x%04x", ctx->ip_offset));
3300 if (IS_STRICT_MODE (ctx) && method->klass != m_class_get_parent (ctx->method->klass) && method->klass != ctx->method->klass)
3301 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));
3303 ctx->super_ctor_called = TRUE;
3304 value = stack_pop_safe (ctx);
3305 if (IS_STRICT_MODE (ctx) && (value->stype & THIS_POINTER_MASK) != THIS_POINTER_MASK)
3306 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid 'this ptr' argument for constructor at 0x%04x", ctx->ip_offset));
3307 if (!(value->stype & UNINIT_THIS_MASK))
3308 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Calling the base constructor on an initialized this pointer at 0x%04x", ctx->ip_offset));
3309 } else {
3310 value = stack_pop (ctx);
3313 copy_stack_value (&copy, value);
3314 //TODO we should extract this to a 'drop_byref_argument' and use everywhere
3315 //Other parts of the code suffer from the same issue of
3316 copy.type = mono_type_get_type_byval (copy.type);
3317 copy.stype &= ~POINTER_MASK;
3319 if (virt_check_this && !stack_slot_is_this_pointer (value) && !(m_class_is_valuetype (method->klass) || stack_slot_is_boxed_value (value)))
3320 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));
3322 if (constrained && virtual_) {
3323 if (!stack_slot_is_managed_pointer (value))
3324 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object is not a managed pointer for a constrained call at 0x%04x", ctx->ip_offset));
3325 if (!mono_metadata_type_equal_full (mono_type_get_type_byval (value->type), mono_type_get_underlying_type (ctx->constrained_type), TRUE))
3326 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object not compatible with constrained type at 0x%04x", ctx->ip_offset));
3327 copy.stype |= BOXED_MASK;
3328 copy.type = ctx->constrained_type;
3329 } else {
3330 if (stack_slot_is_managed_pointer (value) && !m_class_is_valuetype (mono_class_from_mono_type (value->type)))
3331 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));
3333 if (!virtual_ && m_class_is_valuetype (mono_class_from_mono_type (value->type)) && !m_class_is_valuetype (method->klass) && !stack_slot_is_boxed_value (value))
3334 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a valuetype baseclass at 0x%04x", ctx->ip_offset));
3336 if (virtual_ && m_class_is_valuetype (mono_class_from_mono_type (value->type)) && !stack_slot_is_boxed_value (value))
3337 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a valuetype with callvirt at 0x%04x", ctx->ip_offset));
3339 if (m_class_is_valuetype (method->klass) && (stack_slot_is_boxed_value (value) || !stack_slot_is_managed_pointer (value)))
3340 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));
3342 if (!verify_stack_type_compatibility (ctx, type, &copy)) {
3343 char *expected = mono_type_full_name (type);
3344 char *effective = stack_slot_full_name (&copy);
3345 char *method_name = mono_method_full_name (method, TRUE);
3346 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",
3347 expected, effective, method_name, ctx->ip_offset));
3348 g_free (method_name);
3349 g_free (effective);
3350 g_free (expected);
3353 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, mono_class_from_mono_type (value->type))) {
3354 char *name = mono_method_full_name (method, TRUE);
3355 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3356 g_free (name);
3359 } else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
3360 char *name = mono_method_full_name (method, TRUE);
3361 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3362 g_free (name);
3365 if (sig->ret->type != MONO_TYPE_VOID) {
3366 if (!mono_type_is_valid_in_context (ctx, sig->ret))
3367 return;
3369 if (check_overflow (ctx)) {
3370 value = stack_push (ctx);
3371 set_stack_value (ctx, value, sig->ret, FALSE);
3372 if ((ctx->prefix_set & PREFIX_READONLY) && m_class_get_rank (method->klass) && !strcmp (method->name, "Address")) {
3373 ctx->prefix_set &= ~PREFIX_READONLY;
3374 value->stype |= CMMP_MASK;
3376 if (sig->ret->byref && is_safe_byref_call)
3377 value->stype |= SAFE_BYREF_MASK;
3381 if ((ctx->prefix_set & PREFIX_TAIL)) {
3382 if (!mono_delegate_ret_equal (mono_method_signature (ctx->method)->ret, sig->ret))
3383 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call with incompatible return type at 0x%04x", ctx->ip_offset));
3384 if (ctx->header->code [ctx->ip_offset + 5] != CEE_RET)
3385 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call not followed by ret at 0x%04x", ctx->ip_offset));
3390 static void
3391 do_push_static_field (VerifyContext *ctx, int token, gboolean take_addr)
3393 MonoClassField *field;
3394 MonoClass *klass;
3395 if (!check_overflow (ctx))
3396 return;
3397 if (!take_addr)
3398 CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3400 if (!(field = verifier_load_field (ctx, token, &klass, take_addr ? "ldsflda" : "ldsfld")))
3401 return;
3403 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3404 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load non static field at 0x%04x", ctx->ip_offset));
3405 return;
3407 /*taking the address of initonly field only works from the static constructor */
3408 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3409 !(field->parent == ctx->method->klass && (ctx->method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_STATIC)) && !strcmp (".cctor", ctx->method->name)))
3410 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
3412 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3413 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3415 ILStackDesc *value = stack_push (ctx);
3416 set_stack_value (ctx, value, field->type, take_addr);
3417 if (take_addr)
3418 value->stype |= SAFE_BYREF_MASK;
3421 static void
3422 do_store_static_field (VerifyContext *ctx, int token) {
3423 MonoClassField *field;
3424 MonoClass *klass;
3425 ILStackDesc *value;
3426 CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3428 if (!check_underflow (ctx, 1))
3429 return;
3431 value = stack_pop (ctx);
3433 if (!(field = verifier_load_field (ctx, token, &klass, "stsfld")))
3434 return;
3436 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3437 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store non static field at 0x%04x", ctx->ip_offset));
3438 return;
3441 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3442 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type in store static field at 0x%04x", ctx->ip_offset));
3443 return;
3446 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3447 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3449 if (!verify_stack_type_compatibility (ctx, field->type, value)) {
3450 char *stack_name = stack_slot_full_name (value);
3451 char *field_name = mono_type_full_name (field->type);
3452 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type in static field store expected '%s' but found '%s' at 0x%04x",
3453 field_name, stack_name, ctx->ip_offset));
3454 g_free (field_name);
3455 g_free (stack_name);
3459 static gboolean
3460 check_is_valid_type_for_field_ops (VerifyContext *ctx, int token, ILStackDesc *obj, MonoClassField **ret_field, const char *opcode)
3462 MonoClassField *field;
3463 MonoClass *klass;
3464 gboolean is_pointer;
3466 /*must be a reference type, a managed pointer, an unamanaged pointer, or a valuetype*/
3467 if (!(field = verifier_load_field (ctx, token, &klass, opcode)))
3468 return FALSE;
3470 *ret_field = field;
3471 //the value on stack is going to be used as a pointer
3472 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)));
3474 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3475 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type at 0x%04x", ctx->ip_offset));
3476 return FALSE;
3478 g_assert (obj->type);
3480 /*The value on the stack must be a subclass of the defining type of the field*/
3481 /* we need to check if we can load the field from the stack value*/
3482 if (is_pointer) {
3483 if (stack_slot_get_underlying_type (obj) == TYPE_NATIVE_INT)
3484 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Native int is not a verifiable type to reference a field at 0x%04x", ctx->ip_offset));
3486 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3487 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3488 } else {
3489 if (!m_class_is_valuetype (field->parent) && stack_slot_is_managed_pointer (obj))
3490 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));
3492 /*a value type can be loaded from a value or a managed pointer, but not a boxed object*/
3493 if (m_class_is_valuetype (field->parent) && stack_slot_is_boxed_value (obj))
3494 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));
3496 if (!stack_slot_is_null_literal (obj) && !verify_stack_type_compatibility_full (ctx, m_class_get_byval_arg (field->parent), obj, TRUE, FALSE)) {
3497 char *found = stack_slot_full_name (obj);
3498 char *expected = mono_type_full_name (m_class_get_byval_arg (field->parent));
3499 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));
3500 g_free (found);
3501 g_free (expected);
3504 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, mono_class_from_mono_type (obj->type)))
3505 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3508 check_unmanaged_pointer (ctx, obj);
3509 return TRUE;
3512 static void
3513 do_push_field (VerifyContext *ctx, int token, gboolean take_addr)
3515 ILStackDesc *obj;
3516 MonoClassField *field;
3517 gboolean is_safe_byref = FALSE;
3519 if (!take_addr)
3520 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3522 if (!check_underflow (ctx, 1))
3523 return;
3524 obj = stack_pop_safe (ctx);
3526 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, take_addr ? "ldflda" : "ldfld"))
3527 return;
3529 if (take_addr && m_class_is_valuetype (field->parent) && !stack_slot_is_managed_pointer (obj))
3530 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a temporary value-type at 0x%04x", ctx->ip_offset));
3532 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3533 !(field->parent == ctx->method->klass && mono_method_is_constructor (ctx->method)))
3534 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
3536 //must do it here cuz stack_push will return the same slot as obj above
3537 is_safe_byref = take_addr && (stack_slot_is_reference_value (obj) || stack_slot_is_safe_byref (obj));
3539 ILStackDesc *value = stack_push (ctx);
3540 set_stack_value (ctx, value, field->type, take_addr);
3542 if (is_safe_byref)
3543 value->stype |= SAFE_BYREF_MASK;
3546 static void
3547 do_store_field (VerifyContext *ctx, int token)
3549 ILStackDesc *value, *obj;
3550 MonoClassField *field;
3551 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3553 if (!check_underflow (ctx, 2))
3554 return;
3556 value = stack_pop (ctx);
3557 obj = stack_pop_safe (ctx);
3559 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, "stfld"))
3560 return;
3562 if (!verify_stack_type_compatibility (ctx, field->type, value))
3563 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in field store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3566 /*TODO proper handle for Nullable<T>*/
3567 static void
3568 do_box_value (VerifyContext *ctx, int klass_token)
3570 ILStackDesc *value;
3571 MonoType *type = get_boxable_mono_type (ctx, klass_token, "box");
3572 MonoClass *klass;
3574 if (!type)
3575 return;
3577 if (!check_underflow (ctx, 1))
3578 return;
3580 value = stack_pop (ctx);
3581 /*box is a nop for reference types*/
3583 if (stack_slot_get_underlying_type (value) == TYPE_COMPLEX && MONO_TYPE_IS_REFERENCE (value->type) && MONO_TYPE_IS_REFERENCE (type)) {
3584 stack_push_stack_val (ctx, value)->stype |= BOXED_MASK;
3585 return;
3589 if (!verify_stack_type_compatibility (ctx, type, value))
3590 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for boxing operation at 0x%04x", ctx->ip_offset));
3592 klass = mono_class_from_mono_type (type);
3593 if (mono_class_is_nullable (klass))
3594 type = m_class_get_byval_arg (mono_class_get_nullable_param (klass));
3595 stack_push_val (ctx, TYPE_COMPLEX | BOXED_MASK, type);
3598 static void
3599 do_unbox_value (VerifyContext *ctx, int klass_token)
3601 ILStackDesc *value;
3602 MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox");
3604 if (!type)
3605 return;
3607 if (!check_underflow (ctx, 1))
3608 return;
3610 if (!m_class_is_valuetype (mono_class_from_mono_type (type)))
3611 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid reference type for unbox at 0x%04x", ctx->ip_offset));
3613 value = stack_pop (ctx);
3615 /*Value should be: a boxed valuetype or a reference type*/
3616 if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3617 (stack_slot_is_boxed_value (value) || !m_class_is_valuetype (mono_class_from_mono_type (value->type)))))
3618 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));
3620 set_stack_value (ctx, value = stack_push (ctx), mono_type_get_type_byref (type), FALSE);
3621 value->stype |= CMMP_MASK;
3624 static void
3625 do_unbox_any (VerifyContext *ctx, int klass_token)
3627 ILStackDesc *value;
3628 MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox.any");
3630 if (!type)
3631 return;
3633 if (!check_underflow (ctx, 1))
3634 return;
3636 value = stack_pop (ctx);
3638 /*Value should be: a boxed valuetype or a reference type*/
3639 if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3640 (stack_slot_is_boxed_value (value) || !m_class_is_valuetype (mono_class_from_mono_type (value->type)))))
3641 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));
3643 set_stack_value (ctx, stack_push (ctx), type, FALSE);
3646 static void
3647 do_unary_math_op (VerifyContext *ctx, int op)
3649 ILStackDesc *value;
3650 if (!check_underflow (ctx, 1))
3651 return;
3652 value = stack_pop (ctx);
3653 switch (stack_slot_get_type (value)) {
3654 case TYPE_I4:
3655 case TYPE_I8:
3656 case TYPE_NATIVE_INT:
3657 break;
3658 case TYPE_R8:
3659 if (op == CEE_NEG)
3660 break;
3661 case TYPE_COMPLEX: /*only enums are ok*/
3662 if (mono_type_is_enum_type (value->type))
3663 break;
3664 default:
3665 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for unary not at 0x%04x", ctx->ip_offset));
3667 stack_push_stack_val (ctx, value);
3670 static void
3671 do_conversion (VerifyContext *ctx, int kind)
3673 ILStackDesc *value;
3674 if (!check_underflow (ctx, 1))
3675 return;
3676 value = stack_pop (ctx);
3678 switch (stack_slot_get_type (value)) {
3679 case TYPE_I4:
3680 case TYPE_I8:
3681 case TYPE_NATIVE_INT:
3682 case TYPE_R8:
3683 break;
3684 default:
3685 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));
3688 switch (kind) {
3689 case TYPE_I4:
3690 stack_push_val (ctx, TYPE_I4, m_class_get_byval_arg (mono_defaults.int32_class));
3691 break;
3692 case TYPE_I8:
3693 stack_push_val (ctx,TYPE_I8, m_class_get_byval_arg (mono_defaults.int64_class));
3694 break;
3695 case TYPE_R8:
3696 stack_push_val (ctx, TYPE_R8, m_class_get_byval_arg (mono_defaults.double_class));
3697 break;
3698 case TYPE_NATIVE_INT:
3699 stack_push_val (ctx, TYPE_NATIVE_INT, m_class_get_byval_arg (mono_defaults.int_class));
3700 break;
3701 default:
3702 g_error ("unknown type %02x in conversion", kind);
3707 static void
3708 do_load_token (VerifyContext *ctx, int token)
3710 ERROR_DECL (error);
3711 gpointer handle;
3712 MonoClass *handle_class;
3713 if (!check_overflow (ctx))
3714 return;
3716 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
3717 handle = mono_method_get_wrapper_data (ctx->method, token);
3718 handle_class = (MonoClass *)mono_method_get_wrapper_data (ctx->method, token + 1);
3719 if (handle_class == mono_defaults.typehandle_class)
3720 handle = m_class_get_byval_arg ((MonoClass*)handle);
3721 } else {
3722 switch (token & 0xff000000) {
3723 case MONO_TOKEN_TYPE_DEF:
3724 case MONO_TOKEN_TYPE_REF:
3725 case MONO_TOKEN_TYPE_SPEC:
3726 case MONO_TOKEN_FIELD_DEF:
3727 case MONO_TOKEN_METHOD_DEF:
3728 case MONO_TOKEN_METHOD_SPEC:
3729 case MONO_TOKEN_MEMBER_REF:
3730 if (!token_bounds_check (ctx->image, token)) {
3731 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));
3732 return;
3734 break;
3735 default:
3736 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));
3737 return;
3740 handle = mono_ldtoken_checked (ctx->image, token, &handle_class, ctx->generic_context, error);
3743 if (!handle) {
3744 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)));
3745 mono_error_cleanup (error);
3746 return;
3748 if (handle_class == mono_defaults.typehandle_class) {
3749 mono_type_is_valid_in_context (ctx, (MonoType*)handle);
3750 } else if (handle_class == mono_defaults.methodhandle_class) {
3751 mono_method_is_valid_in_context (ctx, (MonoMethod*)handle);
3752 } else if (handle_class == mono_defaults.fieldhandle_class) {
3753 mono_type_is_valid_in_context (ctx, m_class_get_byval_arg (((MonoClassField*)handle)->parent));
3754 } else {
3755 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid ldtoken type %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
3757 stack_push_val (ctx, TYPE_COMPLEX, mono_class_get_type (handle_class));
3760 static void
3761 do_ldobj_value (VerifyContext *ctx, int token)
3763 ILStackDesc *value;
3764 MonoType *type = get_boxable_mono_type (ctx, token, "ldobj");
3765 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3767 if (!type)
3768 return;
3770 if (!check_underflow (ctx, 1))
3771 return;
3773 value = stack_pop (ctx);
3774 if (!stack_slot_is_managed_pointer (value)
3775 && stack_slot_get_type (value) != TYPE_NATIVE_INT
3776 && !(stack_slot_get_type (value) == TYPE_PTR && value->type->type != MONO_TYPE_FNPTR)) {
3777 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid argument %s to ldobj at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3778 return;
3781 if (stack_slot_get_type (value) == TYPE_NATIVE_INT)
3782 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Using native pointer to ldobj at 0x%04x", ctx->ip_offset));
3784 /*We have a byval on the stack, but the comparison must be strict. */
3785 if (!verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (value->type), TRUE))
3786 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldojb operation at 0x%04x", ctx->ip_offset));
3788 set_stack_value (ctx, stack_push (ctx), type, FALSE);
3791 static void
3792 do_stobj (VerifyContext *ctx, int token)
3794 ILStackDesc *dest, *src;
3795 MonoType *type = get_boxable_mono_type (ctx, token, "stobj");
3796 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3798 if (!type)
3799 return;
3801 if (!check_underflow (ctx, 2))
3802 return;
3804 src = stack_pop (ctx);
3805 dest = stack_pop (ctx);
3807 if (stack_slot_is_managed_mutability_pointer (dest))
3808 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stobj at 0x%04x", ctx->ip_offset));
3810 if (!stack_slot_is_managed_pointer (dest))
3811 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of stobj operation at 0x%04x", ctx->ip_offset));
3813 if (stack_slot_is_boxed_value (src) && !MONO_TYPE_IS_REFERENCE (src->type) && !MONO_TYPE_IS_REFERENCE (type))
3814 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));
3816 if (!verify_stack_type_compatibility (ctx, type, src)) {
3817 char *type_name = mono_type_full_name (type);
3818 char *src_name = stack_slot_full_name (src);
3819 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));
3820 g_free (type_name);
3821 g_free (src_name);
3824 if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3825 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of stobj don't match at 0x%04x", ctx->ip_offset));
3828 static void
3829 do_cpobj (VerifyContext *ctx, int token)
3831 ILStackDesc *dest, *src;
3832 MonoType *type = get_boxable_mono_type (ctx, token, "cpobj");
3833 if (!type)
3834 return;
3836 if (!check_underflow (ctx, 2))
3837 return;
3839 src = stack_pop (ctx);
3840 dest = stack_pop (ctx);
3842 if (!stack_slot_is_managed_pointer (src))
3843 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid source of cpobj operation at 0x%04x", ctx->ip_offset));
3845 if (!stack_slot_is_managed_pointer (dest))
3846 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of cpobj operation at 0x%04x", ctx->ip_offset));
3848 if (stack_slot_is_managed_mutability_pointer (dest))
3849 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with cpobj at 0x%04x", ctx->ip_offset));
3851 if (!verify_type_compatibility (ctx, type, mono_type_get_type_byval (src->type)))
3852 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Token and source types of cpobj don't match at 0x%04x", ctx->ip_offset));
3854 if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3855 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of cpobj don't match at 0x%04x", ctx->ip_offset));
3858 static void
3859 do_initobj (VerifyContext *ctx, int token)
3861 ILStackDesc *obj;
3862 MonoType *stack, *type = get_boxable_mono_type (ctx, token, "initobj");
3863 if (!type)
3864 return;
3866 if (!check_underflow (ctx, 1))
3867 return;
3869 obj = stack_pop (ctx);
3871 if (!stack_slot_is_managed_pointer (obj))
3872 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid object address for initobj at 0x%04x", ctx->ip_offset));
3874 if (stack_slot_is_managed_mutability_pointer (obj))
3875 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with initobj at 0x%04x", ctx->ip_offset));
3877 stack = mono_type_get_type_byval (obj->type);
3878 if (MONO_TYPE_IS_REFERENCE (stack)) {
3879 if (!verify_type_compatibility (ctx, stack, type))
3880 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3881 else if (IS_STRICT_MODE (ctx) && !mono_metadata_type_equal (type, stack))
3882 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3883 } else if (!verify_type_compatibility (ctx, stack, type)) {
3884 char *expected_name = mono_type_full_name (type);
3885 char *stack_name = mono_type_full_name (stack);
3887 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));
3888 g_free (expected_name);
3889 g_free (stack_name);
3893 static void
3894 do_newobj (VerifyContext *ctx, int token)
3896 ILStackDesc *value;
3897 int i;
3898 MonoMethodSignature *sig;
3899 MonoMethod *method;
3900 gboolean is_delegate = FALSE;
3902 if (!(method = verifier_load_method (ctx, token, "newobj")))
3903 return;
3905 if (!mono_method_is_constructor (method)) {
3906 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method from token 0x%08x not a constructor at 0x%04x", token, ctx->ip_offset));
3907 return;
3910 if (mono_class_get_flags (method->klass) & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE))
3911 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Trying to instantiate an abstract or interface type at 0x%04x", ctx->ip_offset));
3913 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
3914 char *from = mono_method_full_name (ctx->method, TRUE);
3915 char *to = mono_method_full_name (method, TRUE);
3916 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);
3917 g_free (from);
3918 g_free (to);
3921 //FIXME use mono_method_get_signature_full
3922 sig = mono_method_signature (method);
3923 if (!sig) {
3924 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid constructor signature to newobj at 0x%04x", ctx->ip_offset));
3925 return;
3928 if (!sig->hasthis) {
3929 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid constructor signature missing hasthis at 0x%04x", ctx->ip_offset));
3930 return;
3933 if (!check_underflow (ctx, sig->param_count))
3934 return;
3936 is_delegate = m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class;
3938 if (is_delegate) {
3939 ILStackDesc *funptr;
3940 //first arg is object, second arg is fun ptr
3941 if (sig->param_count != 2) {
3942 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid delegate constructor at 0x%04x", ctx->ip_offset));
3943 return;
3945 funptr = stack_pop (ctx);
3946 value = stack_pop (ctx);
3947 verify_delegate_compatibility (ctx, method->klass, value, funptr);
3948 } else {
3949 for (i = sig->param_count - 1; i >= 0; --i) {
3950 VERIFIER_DEBUG ( printf ("verifying constructor argument %d\n", i); );
3951 value = stack_pop (ctx);
3952 if (!verify_stack_type_compatibility (ctx, sig->params [i], value)) {
3953 char *stack_name = stack_slot_full_name (value);
3954 char *sig_name = mono_type_full_name (sig->params [i]);
3955 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));
3956 g_free (stack_name);
3957 g_free (sig_name);
3960 if (stack_slot_is_managed_mutability_pointer (value))
3961 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer as argument of newobj at 0x%04x", ctx->ip_offset));
3965 if (check_overflow (ctx))
3966 set_stack_value (ctx, stack_push (ctx), m_class_get_byval_arg (method->klass), FALSE);
3969 static void
3970 do_cast (VerifyContext *ctx, int token, const char *opcode) {
3971 ILStackDesc *value;
3972 MonoType *type;
3973 gboolean is_boxed;
3974 gboolean do_box;
3976 if (!check_underflow (ctx, 1))
3977 return;
3979 if (!(type = get_boxable_mono_type (ctx, token, opcode)))
3980 return;
3982 if (type->byref) {
3983 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid %s type at 0x%04x", opcode, ctx->ip_offset));
3984 return;
3987 value = stack_pop (ctx);
3988 is_boxed = stack_slot_is_boxed_value (value);
3990 if (stack_slot_is_managed_pointer (value))
3991 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
3992 else if (!MONO_TYPE_IS_REFERENCE (value->type) && !is_boxed) {
3993 char *name = stack_slot_full_name (value);
3994 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));
3995 g_free (name);
3998 switch (value->type->type) {
3999 case MONO_TYPE_FNPTR:
4000 case MONO_TYPE_PTR:
4001 case MONO_TYPE_TYPEDBYREF:
4002 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
4003 default:
4004 break;
4007 do_box = is_boxed || mono_type_is_generic_argument(type) || m_class_is_valuetype (mono_class_from_mono_type (type));
4008 stack_push_val (ctx, TYPE_COMPLEX | (do_box ? BOXED_MASK : 0), type);
4011 static MonoType *
4012 mono_type_from_opcode (int opcode) {
4013 switch (opcode) {
4014 case CEE_LDIND_I1:
4015 case CEE_LDIND_U1:
4016 case CEE_STIND_I1:
4017 case CEE_LDELEM_I1:
4018 case CEE_LDELEM_U1:
4019 case CEE_STELEM_I1:
4020 return m_class_get_byval_arg (mono_defaults.sbyte_class);
4022 case CEE_LDIND_I2:
4023 case CEE_LDIND_U2:
4024 case CEE_STIND_I2:
4025 case CEE_LDELEM_I2:
4026 case CEE_LDELEM_U2:
4027 case CEE_STELEM_I2:
4028 return m_class_get_byval_arg (mono_defaults.int16_class);
4030 case CEE_LDIND_I4:
4031 case CEE_LDIND_U4:
4032 case CEE_STIND_I4:
4033 case CEE_LDELEM_I4:
4034 case CEE_LDELEM_U4:
4035 case CEE_STELEM_I4:
4036 return m_class_get_byval_arg (mono_defaults.int32_class);
4038 case CEE_LDIND_I8:
4039 case CEE_STIND_I8:
4040 case CEE_LDELEM_I8:
4041 case CEE_STELEM_I8:
4042 return m_class_get_byval_arg (mono_defaults.int64_class);
4044 case CEE_LDIND_R4:
4045 case CEE_STIND_R4:
4046 case CEE_LDELEM_R4:
4047 case CEE_STELEM_R4:
4048 return m_class_get_byval_arg (mono_defaults.single_class);
4050 case CEE_LDIND_R8:
4051 case CEE_STIND_R8:
4052 case CEE_LDELEM_R8:
4053 case CEE_STELEM_R8:
4054 return m_class_get_byval_arg (mono_defaults.double_class);
4056 case CEE_LDIND_I:
4057 case CEE_STIND_I:
4058 case CEE_LDELEM_I:
4059 case CEE_STELEM_I:
4060 return m_class_get_byval_arg (mono_defaults.int_class);
4062 case CEE_LDIND_REF:
4063 case CEE_STIND_REF:
4064 case CEE_LDELEM_REF:
4065 case CEE_STELEM_REF:
4066 return m_class_get_byval_arg (mono_defaults.object_class);
4068 default:
4069 g_error ("unknown opcode %02x in mono_type_from_opcode ", opcode);
4070 return NULL;
4074 static void
4075 do_load_indirect (VerifyContext *ctx, int opcode)
4077 ILStackDesc *value;
4078 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
4080 if (!check_underflow (ctx, 1))
4081 return;
4083 value = stack_pop (ctx);
4084 if (!stack_slot_is_managed_pointer (value)) {
4085 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Load indirect not using a manager pointer at 0x%04x", ctx->ip_offset));
4086 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
4087 return;
4090 if (opcode == CEE_LDIND_REF) {
4091 if (stack_slot_get_underlying_type (value) != TYPE_COMPLEX || m_class_is_valuetype (mono_class_from_mono_type (value->type)))
4092 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind_ref expected object byref operation at 0x%04x", ctx->ip_offset));
4093 set_stack_value (ctx, stack_push (ctx), mono_type_get_type_byval (value->type), FALSE);
4094 } else {
4095 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (value->type), TRUE))
4096 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4097 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
4101 static void
4102 do_store_indirect (VerifyContext *ctx, int opcode)
4104 ILStackDesc *addr, *val;
4105 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
4107 if (!check_underflow (ctx, 2))
4108 return;
4110 val = stack_pop (ctx);
4111 addr = stack_pop (ctx);
4113 check_unmanaged_pointer (ctx, addr);
4115 if (!stack_slot_is_managed_pointer (addr) && stack_slot_get_type (addr) != TYPE_PTR) {
4116 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid non-pointer argument to stind at 0x%04x", ctx->ip_offset));
4117 return;
4120 if (stack_slot_is_managed_mutability_pointer (addr)) {
4121 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stind at 0x%04x", ctx->ip_offset));
4122 return;
4125 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (addr->type), TRUE))
4126 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid addr type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4128 if (!verify_stack_type_compatibility (ctx, mono_type_from_opcode (opcode), val))
4129 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4132 static void
4133 do_newarr (VerifyContext *ctx, int token)
4135 ILStackDesc *value;
4136 MonoType *type = get_boxable_mono_type (ctx, token, "newarr");
4138 if (!type)
4139 return;
4141 if (!check_underflow (ctx, 1))
4142 return;
4144 value = stack_pop (ctx);
4145 if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
4146 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));
4148 set_stack_value (ctx, stack_push (ctx), mono_class_get_type (mono_class_create_array (mono_class_from_mono_type (type), 1)), FALSE);
4151 /*FIXME handle arrays that are not 0-indexed*/
4152 static void
4153 do_ldlen (VerifyContext *ctx)
4155 ILStackDesc *value;
4157 if (!check_underflow (ctx, 1))
4158 return;
4160 value = stack_pop (ctx);
4162 if (stack_slot_get_type (value) != TYPE_COMPLEX || value->type->type != MONO_TYPE_SZARRAY)
4163 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type for ldlen at 0x%04x", ctx->ip_offset));
4165 stack_push_val (ctx, TYPE_NATIVE_INT, m_class_get_byval_arg (mono_defaults.int_class));
4168 /*FIXME handle arrays that are not 0-indexed*/
4169 /*FIXME handle readonly prefix and CMMP*/
4170 static void
4171 do_ldelema (VerifyContext *ctx, int klass_token)
4173 ILStackDesc *index, *array, *res;
4174 MonoType *type = get_boxable_mono_type (ctx, klass_token, "ldelema");
4175 gboolean valid;
4177 if (!type)
4178 return;
4180 if (!check_underflow (ctx, 2))
4181 return;
4183 index = stack_pop (ctx);
4184 array = stack_pop (ctx);
4186 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4187 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));
4189 if (!stack_slot_is_null_literal (array)) {
4190 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
4191 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type(%s) for ldelema at 0x%04x", stack_slot_get_name (array), ctx->ip_offset));
4192 else {
4193 if (get_stack_type (type) == TYPE_I4 || get_stack_type (type) == TYPE_NATIVE_INT) {
4194 valid = verify_type_compatibility_full (ctx, type, m_class_get_byval_arg (array->type->data.klass), TRUE);
4195 } else {
4196 valid = mono_metadata_type_equal (type, m_class_get_byval_arg (array->type->data.klass));
4198 if (!valid)
4199 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelema at 0x%04x", ctx->ip_offset));
4203 res = stack_push (ctx);
4204 set_stack_value (ctx, res, type, TRUE);
4205 if (ctx->prefix_set & PREFIX_READONLY) {
4206 ctx->prefix_set &= ~PREFIX_READONLY;
4207 res->stype |= CMMP_MASK;
4210 res->stype |= SAFE_BYREF_MASK;
4214 * FIXME handle arrays that are not 0-indexed
4215 * FIXME handle readonly prefix and CMMP
4217 static void
4218 do_ldelem (VerifyContext *ctx, int opcode, int token)
4220 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
4221 ILStackDesc *index, *array;
4222 MonoType *type;
4223 if (!check_underflow (ctx, 2))
4224 return;
4226 if (opcode == CEE_LDELEM) {
4227 if (!(type = verifier_load_type (ctx, token, "ldelem.any"))) {
4228 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
4229 return;
4231 } else {
4232 type = mono_type_from_opcode (opcode);
4235 index = stack_pop (ctx);
4236 array = stack_pop (ctx);
4238 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4239 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));
4241 if (!stack_slot_is_null_literal (array)) {
4242 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
4243 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));
4244 else {
4245 if (opcode == CEE_LDELEM_REF) {
4246 if (m_class_is_valuetype (array->type->data.klass))
4247 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for ldelem.ref 0x%04x", ctx->ip_offset));
4248 type = m_class_get_byval_arg (array->type->data.klass);
4249 } else {
4250 MonoType *candidate = m_class_get_byval_arg (array->type->data.klass);
4251 if (IS_STRICT_MODE (ctx)) {
4252 MonoType *underlying_type = mono_type_get_underlying_type_any (type);
4253 MonoType *underlying_candidate = mono_type_get_underlying_type_any (candidate);
4254 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)) ||
4255 (IS_ONE_OF2 (underlying_candidate->type, MONO_TYPE_I4, MONO_TYPE_U4) && IS_ONE_OF2 (underlying_type->type, MONO_TYPE_I, MONO_TYPE_U)))
4256 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
4258 if (!verify_type_compatibility_full (ctx, type, candidate, TRUE))
4259 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
4264 set_stack_value (ctx, stack_push (ctx), type, FALSE);
4265 #undef IS_ONE_OF2
4269 * FIXME handle arrays that are not 0-indexed
4271 static void
4272 do_stelem (VerifyContext *ctx, int opcode, int token)
4274 ILStackDesc *index, *array, *value;
4275 MonoType *type;
4276 if (!check_underflow (ctx, 3))
4277 return;
4279 if (opcode == CEE_STELEM) {
4280 if (!(type = verifier_load_type (ctx, token, "stelem.any"))) {
4281 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
4282 return;
4284 } else {
4285 type = mono_type_from_opcode (opcode);
4288 value = stack_pop (ctx);
4289 index = stack_pop (ctx);
4290 array = stack_pop (ctx);
4292 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4293 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));
4295 if (!stack_slot_is_null_literal (array)) {
4296 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY) {
4297 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));
4298 } else {
4299 if (opcode == CEE_STELEM_REF) {
4300 if (m_class_is_valuetype (array->type->data.klass))
4301 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4302 } else if (!verify_type_compatibility_full (ctx, m_class_get_byval_arg (array->type->data.klass), type, TRUE)) {
4303 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4307 if (opcode == CEE_STELEM_REF) {
4308 if (!stack_slot_is_boxed_value (value) && m_class_is_valuetype (mono_class_from_mono_type (value->type)))
4309 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4310 } else if (opcode != CEE_STELEM_REF) {
4311 if (!verify_stack_type_compatibility (ctx, type, value))
4312 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4314 if (stack_slot_is_boxed_value (value) && !MONO_TYPE_IS_REFERENCE (value->type) && !MONO_TYPE_IS_REFERENCE (type))
4315 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));
4320 static void
4321 do_throw (VerifyContext *ctx)
4323 ILStackDesc *exception;
4324 if (!check_underflow (ctx, 1))
4325 return;
4326 exception = stack_pop (ctx);
4328 if (!stack_slot_is_null_literal (exception) && !(stack_slot_get_type (exception) == TYPE_COMPLEX && !m_class_is_valuetype (mono_class_from_mono_type (exception->type))))
4329 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type on stack for throw, expected reference type at 0x%04x", ctx->ip_offset));
4331 if (mono_type_is_generic_argument (exception->type) && !stack_slot_is_boxed_value (exception)) {
4332 char *name = mono_type_full_name (exception->type);
4333 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));
4334 g_free (name);
4336 /*The stack is left empty after a throw*/
4337 ctx->eval.size = 0;
4341 static void
4342 do_endfilter (VerifyContext *ctx)
4344 MonoExceptionClause *clause;
4346 if (IS_STRICT_MODE (ctx)) {
4347 if (ctx->eval.size != 1)
4348 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack size must have one item for endfilter at 0x%04x", ctx->ip_offset));
4350 if (ctx->eval.size >= 1 && stack_slot_get_type (stack_pop (ctx)) != TYPE_I4)
4351 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack item type is not an int32 for endfilter at 0x%04x", ctx->ip_offset));
4354 if ((clause = is_correct_endfilter (ctx, ctx->ip_offset))) {
4355 if (IS_STRICT_MODE (ctx)) {
4356 if (ctx->ip_offset != clause->handler_offset - 2)
4357 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
4358 } else {
4359 if ((ctx->ip_offset != clause->handler_offset - 2) && !MONO_OFFSET_IN_HANDLER (clause, ctx->ip_offset))
4360 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
4362 } else {
4363 if (IS_STRICT_MODE (ctx) && !is_unverifiable_endfilter (ctx, ctx->ip_offset))
4364 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4365 else
4366 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4369 ctx->eval.size = 0;
4372 static void
4373 do_leave (VerifyContext *ctx, int delta)
4375 int target = ((gint32)ctx->ip_offset) + delta;
4376 if (target >= ctx->code_size || target < 0)
4377 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
4379 if (!is_correct_leave (ctx->header, ctx->ip_offset, target))
4380 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ctx->ip_offset));
4381 ctx->eval.size = 0;
4382 ctx->target = target;
4386 * do_static_branch:
4388 * Verify br and br.s opcodes.
4390 static void
4391 do_static_branch (VerifyContext *ctx, int delta)
4393 int target = ctx->ip_offset + delta;
4394 if (target < 0 || target >= ctx->code_size) {
4395 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("branch target out of code at 0x%04x", ctx->ip_offset));
4396 return;
4399 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4400 case 1:
4401 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4402 break;
4403 case 2:
4404 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4405 break;
4408 ctx->target = target;
4411 static void
4412 do_switch (VerifyContext *ctx, int count, const unsigned char *data)
4414 int i, base = ctx->ip_offset + 5 + count * 4;
4415 ILStackDesc *value;
4417 if (!check_underflow (ctx, 1))
4418 return;
4420 value = stack_pop (ctx);
4422 if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
4423 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to switch at 0x%04x", ctx->ip_offset));
4425 for (i = 0; i < count; ++i) {
4426 int target = base + read32 (data + i * 4);
4428 if (target < 0 || target >= ctx->code_size) {
4429 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x out of code at 0x%04x", i, ctx->ip_offset));
4430 return;
4433 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4434 case 1:
4435 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4436 break;
4437 case 2:
4438 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4439 return;
4441 merge_stacks (ctx, &ctx->eval, &ctx->code [target], FALSE, TRUE);
4445 static void
4446 do_load_function_ptr (VerifyContext *ctx, guint32 token, gboolean virtual_)
4448 ILStackDesc *top;
4449 MonoMethod *method;
4451 if (virtual_ && !check_underflow (ctx, 1))
4452 return;
4454 if (!virtual_ && !check_overflow (ctx))
4455 return;
4457 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
4458 method = (MonoMethod *)mono_method_get_wrapper_data (ctx->method, (guint32)token);
4459 if (!method) {
4460 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4461 return;
4463 } else {
4464 if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
4465 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4466 return;
4469 if (!(method = verifier_load_method (ctx, token, virtual_ ? "ldvirtfrn" : "ldftn")))
4470 return;
4473 if (mono_method_is_constructor (method))
4474 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldftn with a constructor at 0x%04x", ctx->ip_offset));
4476 if (virtual_) {
4477 ILStackDesc *top = stack_pop (ctx);
4479 if (stack_slot_get_type (top) != TYPE_COMPLEX || top->type->type == MONO_TYPE_VALUETYPE)
4480 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to ldvirtftn at 0x%04x", ctx->ip_offset));
4482 if (method->flags & METHOD_ATTRIBUTE_STATIC)
4483 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldvirtftn with a constructor at 0x%04x", ctx->ip_offset));
4485 if (!verify_stack_type_compatibility (ctx, m_class_get_byval_arg (method->klass), top))
4486 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unexpected object for ldvirtftn at 0x%04x", ctx->ip_offset));
4489 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL))
4490 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);
4492 top = stack_push_val(ctx, TYPE_PTR, mono_type_create_fnptr_from_mono_method (ctx, method));
4493 top->method = method;
4496 static void
4497 do_sizeof (VerifyContext *ctx, int token)
4499 MonoType *type;
4501 if (!(type = verifier_load_type (ctx, token, "sizeof")))
4502 return;
4504 if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
4505 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type at 0x%04x", ctx->ip_offset));
4506 return;
4509 if (type->type == MONO_TYPE_VOID) {
4510 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type at 0x%04x", ctx->ip_offset));
4511 return;
4514 if (check_overflow (ctx))
4515 set_stack_value (ctx, stack_push (ctx), m_class_get_byval_arg (mono_defaults.uint32_class), FALSE);
4518 /* Stack top can be of any type, the runtime doesn't care and treat everything as an int. */
4519 static void
4520 do_localloc (VerifyContext *ctx)
4522 if (ctx->eval.size != 1) {
4523 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4524 return;
4527 if (in_any_exception_block (ctx->header, ctx->ip_offset)) {
4528 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4529 return;
4532 /*TODO verify top type*/
4533 /* top = */ stack_pop (ctx);
4535 set_stack_value (ctx, stack_push (ctx), m_class_get_byval_arg (mono_defaults.int_class), FALSE);
4536 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Instruction localloc in never verifiable at 0x%04x", ctx->ip_offset));
4539 static void
4540 do_ldstr (VerifyContext *ctx, guint32 token)
4542 GSList *error = NULL;
4543 if (ctx->method->wrapper_type == MONO_WRAPPER_NONE && !image_is_dynamic (ctx->image)) {
4544 if (mono_metadata_token_code (token) != MONO_TOKEN_STRING) {
4545 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string token %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4546 return;
4549 if (!mono_verifier_verify_string_signature (ctx->image, mono_metadata_token_index (token), &error)) {
4550 if (error)
4551 ctx->list = g_slist_concat (ctx->list, error);
4552 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string index %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4553 return;
4557 if (check_overflow (ctx))
4558 stack_push_val (ctx, TYPE_COMPLEX, m_class_get_byval_arg (mono_defaults.string_class));
4561 static void
4562 do_refanyval (VerifyContext *ctx, int token)
4564 ILStackDesc *top;
4565 MonoType *type;
4566 if (!check_underflow (ctx, 1))
4567 return;
4569 if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4570 return;
4572 top = stack_pop (ctx);
4574 if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4575 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));
4577 set_stack_value (ctx, stack_push (ctx), type, TRUE);
4580 static void
4581 do_refanytype (VerifyContext *ctx)
4583 ILStackDesc *top;
4585 if (!check_underflow (ctx, 1))
4586 return;
4588 top = stack_pop (ctx);
4590 if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4591 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));
4593 set_stack_value (ctx, stack_push (ctx), m_class_get_byval_arg (mono_defaults.typehandle_class), FALSE);
4597 static void
4598 do_mkrefany (VerifyContext *ctx, int token)
4600 ILStackDesc *top;
4601 MonoType *type;
4602 if (!check_underflow (ctx, 1))
4603 return;
4605 if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4606 return;
4608 top = stack_pop (ctx);
4610 if (stack_slot_is_managed_mutability_pointer (top))
4611 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with mkrefany at 0x%04x", ctx->ip_offset));
4613 if (!stack_slot_is_managed_pointer (top)) {
4614 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));
4615 }else {
4616 MonoType *stack_type = mono_type_get_type_byval (top->type);
4617 if (MONO_TYPE_IS_REFERENCE (type) && !mono_metadata_type_equal (type, stack_type))
4618 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4620 if (!MONO_TYPE_IS_REFERENCE (type) && !verify_type_compatibility_full (ctx, type, stack_type, TRUE))
4621 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4624 set_stack_value (ctx, stack_push (ctx), m_class_get_byval_arg (mono_defaults.typed_reference_class), FALSE);
4627 static void
4628 do_ckfinite (VerifyContext *ctx)
4630 ILStackDesc *top;
4631 if (!check_underflow (ctx, 1))
4632 return;
4634 top = stack_pop (ctx);
4636 if (stack_slot_get_underlying_type (top) != TYPE_R8)
4637 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));
4638 stack_push_stack_val (ctx, top);
4641 * merge_stacks:
4642 * Merge the stacks and perform compat checks. The merge check if types of @from are mergeable with type of @to
4644 * @from holds new values for a given control path
4645 * @to holds the current values of a given control path
4647 * TODO we can eliminate the from argument as all callers pass &ctx->eval
4649 static void
4650 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external)
4652 ERROR_DECL (error);
4653 int i, j;
4654 stack_init (ctx, to);
4656 if (start) {
4657 if (to->flags == IL_CODE_FLAG_NOT_PROCESSED)
4658 from->size = 0;
4659 else
4660 stack_copy (&ctx->eval, to);
4661 goto end_verify;
4662 } else if (!(to->flags & IL_CODE_STACK_MERGED)) {
4663 stack_copy (to, &ctx->eval);
4664 goto end_verify;
4666 VERIFIER_DEBUG ( printf ("performing stack merge %d x %d\n", from->size, to->size); );
4668 if (from->size != to->size) {
4669 VERIFIER_DEBUG ( printf ("different stack sizes %d x %d at 0x%04x\n", from->size, to->size, ctx->ip_offset); );
4670 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));
4671 goto end_verify;
4674 //FIXME we need to preserve CMMP attributes
4675 //FIXME we must take null literals into consideration.
4676 for (i = 0; i < from->size; ++i) {
4677 ILStackDesc *new_slot = from->stack + i;
4678 ILStackDesc *old_slot = to->stack + i;
4679 MonoType *new_type = mono_type_from_stack_slot (new_slot);
4680 MonoType *old_type = mono_type_from_stack_slot (old_slot);
4681 MonoClass *old_class = mono_class_from_mono_type (old_type);
4682 MonoClass *new_class = mono_class_from_mono_type (new_type);
4683 MonoClass *match_class = NULL;
4685 // check for safe byref before the next steps override new_slot
4686 if (stack_slot_is_safe_byref (old_slot) ^ stack_slot_is_safe_byref (new_slot)) {
4687 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));
4688 goto end_verify;
4691 // S := T then U = S (new value is compatible with current value, keep current)
4692 if (verify_stack_type_compatibility (ctx, old_type, new_slot)) {
4693 copy_stack_value (new_slot, old_slot);
4694 continue;
4697 // T := S then U = T (old value is compatible with current value, use new)
4698 if (verify_stack_type_compatibility (ctx, new_type, old_slot)) {
4699 copy_stack_value (old_slot, new_slot);
4700 continue;
4703 /*Both slots are the same boxed valuetype. Simply copy it.*/
4704 if (stack_slot_is_boxed_value (old_slot) &&
4705 stack_slot_is_boxed_value (new_slot) &&
4706 mono_metadata_type_equal (old_type, new_type)) {
4707 copy_stack_value (new_slot, old_slot);
4708 continue;
4711 if (mono_type_is_generic_argument (old_type) || mono_type_is_generic_argument (new_type)) {
4712 char *old_name = stack_slot_full_name (old_slot);
4713 char *new_name = stack_slot_full_name (new_slot);
4714 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));
4715 g_free (old_name);
4716 g_free (new_name);
4717 goto end_verify;
4720 //both are reference types, use closest common super type
4721 if (!m_class_is_valuetype (mono_class_from_mono_type (old_type))
4722 && !m_class_is_valuetype (mono_class_from_mono_type (new_type))
4723 && !stack_slot_is_managed_pointer (old_slot)
4724 && !stack_slot_is_managed_pointer (new_slot)) {
4726 mono_class_setup_supertypes (old_class);
4727 mono_class_setup_supertypes (new_class);
4729 MonoClass **old_class_supertypes = m_class_get_supertypes (old_class);
4730 MonoClass **new_class_supertypes = m_class_get_supertypes (new_class);
4731 for (j = MIN (m_class_get_idepth (old_class), m_class_get_idepth (new_class)) - 1; j > 0; --j) {
4732 if (mono_metadata_type_equal (m_class_get_byval_arg (old_class_supertypes [j]), m_class_get_byval_arg (new_class_supertypes [j]))) {
4733 match_class = old_class_supertypes [j];
4734 goto match_found;
4738 mono_class_setup_interfaces (old_class, error);
4739 if (!mono_error_ok (error)) {
4740 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));
4741 mono_error_cleanup (error);
4742 goto end_verify;
4744 mono_class_setup_interfaces (new_class, error);
4745 if (!mono_error_ok (error)) {
4746 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));
4747 mono_error_cleanup (error);
4748 goto end_verify;
4751 /* if old class is an interface that new class implements */
4752 if (mono_class_is_interface (old_class)) {
4753 if (verifier_class_is_assignable_from (old_class, new_class)) {
4754 match_class = old_class;
4755 goto match_found;
4757 MonoClass **old_class_interfaces = m_class_get_interfaces (old_class);
4758 guint16 old_class_interface_count = m_class_get_interface_count (old_class);
4759 for (j = 0; j < old_class_interface_count; ++j) {
4760 if (verifier_class_is_assignable_from (old_class_interfaces [j], new_class)) {
4761 match_class = old_class_interfaces [j];
4762 goto match_found;
4767 if (mono_class_is_interface (new_class)) {
4768 if (verifier_class_is_assignable_from (new_class, old_class)) {
4769 match_class = new_class;
4770 goto match_found;
4772 MonoClass **new_class_interfaces = m_class_get_interfaces (new_class);
4773 guint16 new_class_interface_count = m_class_get_interface_count (new_class);
4774 for (j = 0; j < new_class_interface_count; ++j) {
4775 if (verifier_class_is_assignable_from (new_class_interfaces [j], old_class)) {
4776 match_class = new_class_interfaces [j];
4777 goto match_found;
4782 //No decent super type found, use object
4783 match_class = mono_defaults.object_class;
4784 goto match_found;
4785 } 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)) {
4786 match_class = mono_defaults.object_class;
4787 goto match_found;
4791 char *old_name = stack_slot_full_name (old_slot);
4792 char *new_name = stack_slot_full_name (new_slot);
4793 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));
4794 g_free (old_name);
4795 g_free (new_name);
4797 set_stack_value (ctx, old_slot, m_class_get_byval_arg (new_class), stack_slot_is_managed_pointer (old_slot));
4798 goto end_verify;
4800 match_found:
4801 g_assert (match_class);
4802 set_stack_value (ctx, old_slot, m_class_get_byval_arg (match_class), stack_slot_is_managed_pointer (old_slot));
4803 set_stack_value (ctx, new_slot, m_class_get_byval_arg (match_class), stack_slot_is_managed_pointer (old_slot));
4804 continue;
4807 end_verify:
4808 if (external)
4809 to->flags |= IL_CODE_FLAG_WAS_TARGET;
4810 to->flags |= IL_CODE_STACK_MERGED;
4813 #define HANDLER_START(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER ? (clause)->data.filter_offset : clause->handler_offset)
4814 #define IS_CATCH_OR_FILTER(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER || (clause)->flags == MONO_EXCEPTION_CLAUSE_NONE)
4817 * is_clause_in_range :
4819 * Returns TRUE if either the protected block or the handler of @clause is in the @start - @end range.
4821 static gboolean
4822 is_clause_in_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4824 if (clause->try_offset >= start && clause->try_offset < end)
4825 return TRUE;
4826 if (HANDLER_START (clause) >= start && HANDLER_START (clause) < end)
4827 return TRUE;
4828 return FALSE;
4832 * is_clause_inside_range :
4834 * Returns TRUE if @clause lies completely inside the @start - @end range.
4836 static gboolean
4837 is_clause_inside_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4839 if (clause->try_offset < start || (clause->try_offset + clause->try_len) > end)
4840 return FALSE;
4841 if (HANDLER_START (clause) < start || (clause->handler_offset + clause->handler_len) > end)
4842 return FALSE;
4843 return TRUE;
4847 * is_clause_nested :
4849 * Returns TRUE if @nested is nested in @clause.
4851 static gboolean
4852 is_clause_nested (MonoExceptionClause *clause, MonoExceptionClause *nested)
4854 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (nested, clause->data.filter_offset, clause->handler_offset))
4855 return TRUE;
4856 return is_clause_inside_range (nested, clause->try_offset, clause->try_offset + clause->try_len) ||
4857 is_clause_inside_range (nested, clause->handler_offset, clause->handler_offset + clause->handler_len);
4860 /* Test the relationship between 2 exception clauses. Follow P.1 12.4.2.7 of ECMA
4861 * the each pair of exception must have the following properties:
4862 * - one is fully nested on another (the outer must not be a filter clause) (the nested one must come earlier)
4863 * - completely disjoin (none of the 3 regions of each entry overlap with the other 3)
4864 * - mutual protection (protected block is EXACT the same, handlers are disjoin and all handler are catch or all handler are filter)
4866 static void
4867 verify_clause_relationship (VerifyContext *ctx, MonoExceptionClause *clause, MonoExceptionClause *to_test)
4869 /*clause is nested*/
4870 if (to_test->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (clause, to_test->data.filter_offset, to_test->handler_offset)) {
4871 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clause inside filter"));
4872 return;
4875 /*wrong nesting order.*/
4876 if (is_clause_nested (clause, to_test)) {
4877 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Nested exception clause appears after enclosing clause"));
4878 return;
4881 /*mutual protection*/
4882 if (clause->try_offset == to_test->try_offset && clause->try_len == to_test->try_len) {
4883 /*handlers are not disjoint*/
4884 if (is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) {
4885 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception handlers overlap"));
4886 return;
4888 /* handlers are not catch or filter */
4889 if (!IS_CATCH_OR_FILTER (clause) || !IS_CATCH_OR_FILTER (to_test)) {
4890 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses with shared protected block are neither catch or filter"));
4891 return;
4893 /*OK*/
4894 return;
4897 /*not completelly disjoint*/
4898 if ((is_clause_in_range (to_test, clause->try_offset, clause->try_offset + clause->try_len) ||
4899 is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) && !is_clause_nested (to_test, clause))
4900 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses overlap"));
4903 #define code_bounds_check(size) \
4904 if (ADDP_IS_GREATER_OR_OVF (ip, size, end)) {\
4905 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Code overrun starting with 0x%x at 0x%04x", *ip, ctx.ip_offset)); \
4906 break; \
4909 static gboolean
4910 mono_opcode_is_prefix (int op)
4912 switch (op) {
4913 case MONO_CEE_UNALIGNED_:
4914 case MONO_CEE_VOLATILE_:
4915 case MONO_CEE_TAIL_:
4916 case MONO_CEE_CONSTRAINED_:
4917 case MONO_CEE_READONLY_:
4918 return TRUE;
4920 return FALSE;
4924 * FIXME: need to distinguish between valid and verifiable.
4925 * Need to keep track of types on the stack.
4929 * mono_method_verify:
4930 * Verify types for opcodes.
4932 GSList*
4933 mono_method_verify (MonoMethod *method, int level)
4935 ERROR_DECL (error);
4936 const unsigned char *ip, *code_start;
4937 const unsigned char *end;
4938 MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
4940 int i, n, need_merge = 0, start = 0;
4941 guint ip_offset = 0, prefix = 0;
4942 MonoGenericContext *generic_context = NULL;
4943 MonoImage *image;
4944 VerifyContext ctx;
4945 GSList *tmp;
4946 VERIFIER_DEBUG ( printf ("Verify IL for method %s %s %s\n", method->klass->name_space, method->klass->name, method->name); );
4948 init_verifier_stats ();
4950 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
4951 (method->flags & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT))) {
4952 return NULL;
4955 memset (&ctx, 0, sizeof (VerifyContext));
4957 //FIXME use mono_method_get_signature_full
4958 ctx.signature = mono_method_signature (method);
4959 if (!ctx.signature) {
4960 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method signature"));
4962 finish_collect_stats ();
4963 return ctx.list;
4965 if (!method->is_generic && !mono_class_is_gtd (method->klass) && ctx.signature->has_type_parameters) {
4966 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Method and signature don't match in terms of genericity"));
4967 finish_collect_stats ();
4968 return ctx.list;
4971 ctx.header = mono_method_get_header_checked (method, error);
4972 if (!ctx.header) {
4973 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method header due to %s", mono_error_get_message (error)));
4974 mono_error_cleanup (error);
4975 finish_collect_stats ();
4976 return ctx.list;
4978 ctx.method = method;
4979 code_start = ip = ctx.header->code;
4980 end = ip + ctx.header->code_size;
4981 ctx.image = image = m_class_get_image (method->klass);
4984 ctx.max_args = ctx.signature->param_count + ctx.signature->hasthis;
4985 ctx.max_stack = ctx.header->max_stack;
4986 ctx.verifiable = ctx.valid = 1;
4987 ctx.level = level;
4989 ctx.code = g_new (ILCodeDesc, ctx.header->code_size);
4990 ctx.code_size = ctx.header->code_size;
4991 _MEM_ALLOC (sizeof (ILCodeDesc) * ctx.header->code_size);
4993 memset(ctx.code, 0, sizeof (ILCodeDesc) * ctx.header->code_size);
4995 ctx.num_locals = ctx.header->num_locals;
4996 ctx.locals = (MonoType **)g_memdup (ctx.header->locals, sizeof (MonoType*) * ctx.header->num_locals);
4997 _MEM_ALLOC (sizeof (MonoType*) * ctx.header->num_locals);
4998 ctx.locals_verification_state = g_new0 (char, ctx.num_locals);
5000 if (ctx.num_locals > 0 && !ctx.header->init_locals)
5001 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Method with locals variable but without init locals set"));
5003 ctx.params = g_new (MonoType*, ctx.max_args);
5004 _MEM_ALLOC (sizeof (MonoType*) * ctx.max_args);
5006 if (ctx.signature->hasthis)
5007 ctx.params [0] = m_class_is_valuetype (method->klass) ? m_class_get_this_arg (method->klass) : m_class_get_byval_arg (method->klass);
5008 memcpy (ctx.params + ctx.signature->hasthis, ctx.signature->params, sizeof (MonoType *) * ctx.signature->param_count);
5010 if (ctx.signature->is_inflated)
5011 ctx.generic_context = generic_context = mono_method_get_context (method);
5013 if (!generic_context && (mono_class_is_gtd (method->klass) || method->is_generic)) {
5014 if (method->is_generic)
5015 ctx.generic_context = generic_context = &(mono_method_get_generic_container (method)->context);
5016 else
5017 ctx.generic_context = generic_context = &mono_class_get_generic_container (method->klass)->context;
5020 for (i = 0; i < ctx.num_locals; ++i) {
5021 MonoType *uninflated = ctx.locals [i];
5022 ctx.locals [i] = mono_class_inflate_generic_type_checked (ctx.locals [i], ctx.generic_context, error);
5023 if (!mono_error_ok (error)) {
5024 char *name = mono_type_full_name (ctx.locals [i] ? ctx.locals [i] : uninflated);
5025 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %d of type %s", i, name));
5026 g_free (name);
5027 mono_error_cleanup (error);
5028 /* we must not free (in cleanup) what was not yet allocated (but only copied) */
5029 ctx.num_locals = i;
5030 ctx.max_args = 0;
5031 goto cleanup;
5034 for (i = 0; i < ctx.max_args; ++i) {
5035 MonoType *uninflated = ctx.params [i];
5036 ctx.params [i] = mono_class_inflate_generic_type_checked (ctx.params [i], ctx.generic_context, error);
5037 if (!mono_error_ok (error)) {
5038 char *name = mono_type_full_name (ctx.params [i] ? ctx.params [i] : uninflated);
5039 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %d of type %s", i, name));
5040 g_free (name);
5041 mono_error_cleanup (error);
5042 /* we must not free (in cleanup) what was not yet allocated (but only copied) */
5043 ctx.max_args = i;
5044 goto cleanup;
5047 stack_init (&ctx, &ctx.eval);
5049 for (i = 0; i < ctx.num_locals; ++i) {
5050 if (!mono_type_is_valid_in_context (&ctx, ctx.locals [i]))
5051 break;
5052 if (get_stack_type (ctx.locals [i]) == TYPE_INV) {
5053 char *name = mono_type_full_name (ctx.locals [i]);
5054 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %i of type %s", i, name));
5055 g_free (name);
5056 break;
5061 for (i = 0; i < ctx.max_args; ++i) {
5062 if (!mono_type_is_valid_in_context (&ctx, ctx.params [i]))
5063 break;
5065 if (get_stack_type (ctx.params [i]) == TYPE_INV) {
5066 char *name = mono_type_full_name (ctx.params [i]);
5067 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %i of type %s", i, name));
5068 g_free (name);
5069 break;
5073 if (!ctx.valid)
5074 goto cleanup;
5076 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
5077 MonoExceptionClause *clause = ctx.header->clauses + i;
5078 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); );
5080 if (clause->try_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, ctx.code_size))
5081 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause out of bounds at 0x%04x", clause->try_offset));
5083 if (clause->try_len <= 0)
5084 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause len <= 0 at 0x%04x", clause->try_offset));
5086 if (clause->handler_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->handler_offset, clause->handler_len, ctx.code_size))
5087 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause out of bounds at 0x%04x", clause->try_offset));
5089 if (clause->handler_len <= 0)
5090 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause len <= 0 at 0x%04x", clause->try_offset));
5092 if (clause->try_offset < clause->handler_offset && ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, HANDLER_START (clause)))
5093 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try block (at 0x%04x) includes handler block (at 0x%04x)", clause->try_offset, clause->handler_offset));
5095 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5096 if (clause->data.filter_offset > ctx.code_size)
5097 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause out of bounds at 0x%04x", clause->try_offset));
5099 if (clause->data.filter_offset >= clause->handler_offset)
5100 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause must come before the handler clause at 0x%04x", clause->data.filter_offset));
5103 for (n = i + 1; n < ctx.header->num_clauses && ctx.valid; ++n)
5104 verify_clause_relationship (&ctx, clause, ctx.header->clauses + n);
5106 if (!ctx.valid)
5107 break;
5109 ctx.code [clause->try_offset].flags |= IL_CODE_FLAG_WAS_TARGET;
5110 if (clause->try_offset + clause->try_len < ctx.code_size)
5111 ctx.code [clause->try_offset + clause->try_len].flags |= IL_CODE_FLAG_WAS_TARGET;
5112 if (clause->handler_offset + clause->handler_len < ctx.code_size)
5113 ctx.code [clause->handler_offset + clause->handler_len].flags |= IL_CODE_FLAG_WAS_TARGET;
5115 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
5116 if (!clause->data.catch_class) {
5117 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Catch clause %d with invalid type", i));
5118 break;
5120 if (!mono_type_is_valid_in_context (&ctx, m_class_get_byval_arg (clause->data.catch_class)))
5121 break;
5123 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, clause->data.catch_class);
5125 else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5126 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->data.filter_offset, mono_defaults.exception_class);
5127 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, mono_defaults.exception_class);
5131 if (!ctx.valid)
5132 goto cleanup;
5134 original_bb = bb = mono_basic_block_split (method, error, ctx.header);
5135 if (!mono_error_ok (error)) {
5136 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid branch target: %s", mono_error_get_message (error)));
5137 mono_error_cleanup (error);
5138 goto cleanup;
5140 g_assert (bb);
5142 while (ip < end && ctx.valid) {
5143 int op_size;
5144 ip_offset = (guint) (ip - code_start);
5146 const unsigned char *ip_copy = ip;
5147 int op;
5149 if (ip_offset > bb->end) {
5150 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block at [0x%04x] targets middle instruction at 0x%04x", bb->end, ip_offset));
5151 goto cleanup;
5154 if (ip_offset == bb->end)
5155 bb = bb->next;
5157 op_size = mono_opcode_value_and_size (&ip_copy, end, &op);
5158 if (op_size == -1) {
5159 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ip_offset));
5160 goto cleanup;
5163 if (ADD_IS_GREATER_OR_OVF (ip_offset, op_size, bb->end)) {
5164 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block targets middle of instruction at 0x%04x", ip_offset));
5165 goto cleanup;
5168 /*Last Instruction*/
5169 if (ip_offset + op_size == bb->end && mono_opcode_is_prefix (op)) {
5170 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));
5171 goto cleanup;
5175 ctx.ip_offset = ip_offset = (guint) (ip - code_start);
5177 /*We need to check against fallthrou in and out of protected blocks.
5178 * For fallout we check the once a protected block ends, if the start flag is not set.
5179 * Likewise for fallthru in, we check if ip is the start of a protected block and start is not set
5180 * TODO convert these checks to be done using flags and not this loop
5182 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
5183 MonoExceptionClause *clause = ctx.header->clauses + i;
5185 if ((clause->try_offset + clause->try_len == ip_offset) && start == 0) {
5186 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru off try block at 0x%04x", ip_offset));
5187 start = 1;
5190 if ((clause->handler_offset + clause->handler_len == ip_offset) && start == 0) {
5191 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
5192 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
5193 else
5194 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
5195 start = 1;
5198 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && clause->handler_offset == ip_offset && start == 0) {
5199 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of filter block at 0x%04x", ip_offset));
5200 start = 1;
5203 if (clause->handler_offset == ip_offset && start == 0) {
5204 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru handler block at 0x%04x", ip_offset));
5205 start = 1;
5208 if (clause->try_offset == ip_offset && ctx.eval.size > 0 && start == 0) {
5209 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Try to enter try block with a non-empty stack at 0x%04x", ip_offset));
5210 start = 1;
5214 /*This must be done after fallthru detection otherwise it won't happen.*/
5215 if (bb->dead) {
5216 /*FIXME remove this once we move all bad branch checking code to use BB only*/
5217 ctx.code [ip_offset].flags |= IL_CODE_FLAG_SEEN;
5218 ip += op_size;
5219 continue;
5222 if (!ctx.valid)
5223 break;
5225 if (need_merge) {
5226 VERIFIER_DEBUG ( printf ("extra merge needed! 0x%04x \n", ctx.target); );
5227 merge_stacks (&ctx, &ctx.eval, &ctx.code [ctx.target], FALSE, TRUE);
5228 need_merge = 0;
5230 merge_stacks (&ctx, &ctx.eval, &ctx.code[ip_offset], start, FALSE);
5231 start = 0;
5233 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
5234 #ifdef MONO_VERIFIER_DEBUG
5236 char *discode;
5237 discode = mono_disasm_code_one (NULL, method, ip, NULL);
5238 discode [strlen (discode) - 1] = 0; /* no \n */
5239 g_print ("[%d] %-29s (%d)\n", ip_offset, discode, ctx.eval.size);
5240 g_free (discode);
5242 dump_stack_state (&ctx.code [ip_offset]);
5243 dump_stack_state (&ctx.eval);
5244 #endif
5246 switch (*ip) {
5247 case CEE_NOP:
5248 case CEE_BREAK:
5249 ++ip;
5250 break;
5252 case CEE_LDARG_0:
5253 case CEE_LDARG_1:
5254 case CEE_LDARG_2:
5255 case CEE_LDARG_3:
5256 push_arg (&ctx, *ip - CEE_LDARG_0, FALSE);
5257 ++ip;
5258 break;
5260 case CEE_LDARG_S:
5261 case CEE_LDARGA_S:
5262 code_bounds_check (2);
5263 push_arg (&ctx, ip [1], *ip == CEE_LDARGA_S);
5264 ip += 2;
5265 break;
5267 case CEE_ADD_OVF_UN:
5268 do_binop (&ctx, *ip, add_ovf_un_table);
5269 ++ip;
5270 break;
5272 case CEE_SUB_OVF_UN:
5273 do_binop (&ctx, *ip, sub_ovf_un_table);
5274 ++ip;
5275 break;
5277 case CEE_ADD_OVF:
5278 case CEE_SUB_OVF:
5279 case CEE_MUL_OVF:
5280 case CEE_MUL_OVF_UN:
5281 do_binop (&ctx, *ip, bin_ovf_table);
5282 ++ip;
5283 break;
5285 case CEE_ADD:
5286 do_binop (&ctx, *ip, add_table);
5287 ++ip;
5288 break;
5290 case CEE_SUB:
5291 do_binop (&ctx, *ip, sub_table);
5292 ++ip;
5293 break;
5295 case CEE_MUL:
5296 case CEE_DIV:
5297 case CEE_REM:
5298 do_binop (&ctx, *ip, bin_op_table);
5299 ++ip;
5300 break;
5302 case CEE_AND:
5303 case CEE_DIV_UN:
5304 case CEE_OR:
5305 case CEE_REM_UN:
5306 case CEE_XOR:
5307 do_binop (&ctx, *ip, int_bin_op_table);
5308 ++ip;
5309 break;
5311 case CEE_SHL:
5312 case CEE_SHR:
5313 case CEE_SHR_UN:
5314 do_binop (&ctx, *ip, shift_op_table);
5315 ++ip;
5316 break;
5318 case CEE_POP:
5319 if (!check_underflow (&ctx, 1))
5320 break;
5321 stack_pop_safe (&ctx);
5322 ++ip;
5323 break;
5325 case CEE_RET:
5326 do_ret (&ctx);
5327 ++ip;
5328 start = 1;
5329 break;
5331 case CEE_LDLOC_0:
5332 case CEE_LDLOC_1:
5333 case CEE_LDLOC_2:
5334 case CEE_LDLOC_3:
5335 /*TODO support definite assignment verification? */
5336 push_local (&ctx, *ip - CEE_LDLOC_0, FALSE);
5337 ++ip;
5338 break;
5340 case CEE_STLOC_0:
5341 case CEE_STLOC_1:
5342 case CEE_STLOC_2:
5343 case CEE_STLOC_3:
5344 store_local (&ctx, *ip - CEE_STLOC_0);
5345 ++ip;
5346 break;
5348 case CEE_STLOC_S:
5349 code_bounds_check (2);
5350 store_local (&ctx, ip [1]);
5351 ip += 2;
5352 break;
5354 case CEE_STARG_S:
5355 code_bounds_check (2);
5356 store_arg (&ctx, ip [1]);
5357 ip += 2;
5358 break;
5360 case CEE_LDC_I4_M1:
5361 case CEE_LDC_I4_0:
5362 case CEE_LDC_I4_1:
5363 case CEE_LDC_I4_2:
5364 case CEE_LDC_I4_3:
5365 case CEE_LDC_I4_4:
5366 case CEE_LDC_I4_5:
5367 case CEE_LDC_I4_6:
5368 case CEE_LDC_I4_7:
5369 case CEE_LDC_I4_8:
5370 if (check_overflow (&ctx))
5371 stack_push_val (&ctx, TYPE_I4, m_class_get_byval_arg (mono_defaults.int32_class));
5372 ++ip;
5373 break;
5375 case CEE_LDC_I4_S:
5376 code_bounds_check (2);
5377 if (check_overflow (&ctx))
5378 stack_push_val (&ctx, TYPE_I4, m_class_get_byval_arg (mono_defaults.int32_class));
5379 ip += 2;
5380 break;
5382 case CEE_LDC_I4:
5383 code_bounds_check (5);
5384 if (check_overflow (&ctx))
5385 stack_push_val (&ctx,TYPE_I4, m_class_get_byval_arg (mono_defaults.int32_class));
5386 ip += 5;
5387 break;
5389 case CEE_LDC_I8:
5390 code_bounds_check (9);
5391 if (check_overflow (&ctx))
5392 stack_push_val (&ctx,TYPE_I8, m_class_get_byval_arg (mono_defaults.int64_class));
5393 ip += 9;
5394 break;
5396 case CEE_LDC_R4:
5397 code_bounds_check (5);
5398 if (check_overflow (&ctx))
5399 stack_push_val (&ctx, TYPE_R8, m_class_get_byval_arg (mono_defaults.double_class));
5400 ip += 5;
5401 break;
5403 case CEE_LDC_R8:
5404 code_bounds_check (9);
5405 if (check_overflow (&ctx))
5406 stack_push_val (&ctx, TYPE_R8, m_class_get_byval_arg (mono_defaults.double_class));
5407 ip += 9;
5408 break;
5410 case CEE_LDNULL:
5411 if (check_overflow (&ctx))
5412 stack_push_val (&ctx, TYPE_COMPLEX | NULL_LITERAL_MASK, m_class_get_byval_arg (mono_defaults.object_class));
5413 ++ip;
5414 break;
5416 case CEE_BEQ_S:
5417 case CEE_BNE_UN_S:
5418 code_bounds_check (2);
5419 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_eq_op);
5420 ip += 2;
5421 need_merge = 1;
5422 break;
5424 case CEE_BGE_S:
5425 case CEE_BGT_S:
5426 case CEE_BLE_S:
5427 case CEE_BLT_S:
5428 case CEE_BGE_UN_S:
5429 case CEE_BGT_UN_S:
5430 case CEE_BLE_UN_S:
5431 case CEE_BLT_UN_S:
5432 code_bounds_check (2);
5433 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_op);
5434 ip += 2;
5435 need_merge = 1;
5436 break;
5438 case CEE_BEQ:
5439 case CEE_BNE_UN:
5440 code_bounds_check (5);
5441 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_eq_op);
5442 ip += 5;
5443 need_merge = 1;
5444 break;
5446 case CEE_BGE:
5447 case CEE_BGT:
5448 case CEE_BLE:
5449 case CEE_BLT:
5450 case CEE_BGE_UN:
5451 case CEE_BGT_UN:
5452 case CEE_BLE_UN:
5453 case CEE_BLT_UN:
5454 code_bounds_check (5);
5455 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_op);
5456 ip += 5;
5457 need_merge = 1;
5458 break;
5460 case CEE_LDLOC_S:
5461 case CEE_LDLOCA_S:
5462 code_bounds_check (2);
5463 push_local (&ctx, ip[1], *ip == CEE_LDLOCA_S);
5464 ip += 2;
5465 break;
5467 case CEE_UNUSED99:
5468 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5469 ++ip;
5470 break;
5472 case CEE_DUP: {
5473 ILStackDesc *top;
5474 if (!check_underflow (&ctx, 1))
5475 break;
5476 if (!check_overflow (&ctx))
5477 break;
5478 top = stack_push (&ctx);
5479 copy_stack_value (top, stack_peek (&ctx, 1));
5480 ++ip;
5481 break;
5484 case CEE_JMP:
5485 code_bounds_check (5);
5486 if (ctx.eval.size)
5487 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Eval stack must be empty in jmp at 0x%04x", ip_offset));
5488 /* token = read32 (ip + 1); */
5489 if (in_any_block (ctx.header, ip_offset))
5490 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("jmp cannot escape exception blocks at 0x%04x", ip_offset));
5492 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction jmp is not verifiable at 0x%04x", ctx.ip_offset));
5494 * FIXME: check signature, retval, arguments etc.
5496 ip += 5;
5497 break;
5498 case CEE_CALL:
5499 case CEE_CALLVIRT:
5500 code_bounds_check (5);
5501 do_invoke_method (&ctx, read32 (ip + 1), *ip == CEE_CALLVIRT);
5502 ip += 5;
5503 break;
5505 case CEE_CALLI:
5506 code_bounds_check (5);
5507 /* token = read32 (ip + 1); */
5509 * FIXME: check signature, retval, arguments etc.
5510 * FIXME: check requirements for tail call
5512 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction calli is not verifiable at 0x%04x", ctx.ip_offset));
5513 ip += 5;
5514 break;
5515 case CEE_BR_S:
5516 code_bounds_check (2);
5517 do_static_branch (&ctx, (signed char)ip [1] + 2);
5518 need_merge = 1;
5519 ip += 2;
5520 start = 1;
5521 break;
5523 case CEE_BRFALSE_S:
5524 case CEE_BRTRUE_S:
5525 code_bounds_check (2);
5526 do_boolean_branch_op (&ctx, (signed char)ip [1] + 2);
5527 ip += 2;
5528 need_merge = 1;
5529 break;
5531 case CEE_BR:
5532 code_bounds_check (5);
5533 do_static_branch (&ctx, (gint32)read32 (ip + 1) + 5);
5534 need_merge = 1;
5535 ip += 5;
5536 start = 1;
5537 break;
5539 case CEE_BRFALSE:
5540 case CEE_BRTRUE:
5541 code_bounds_check (5);
5542 do_boolean_branch_op (&ctx, (gint32)read32 (ip + 1) + 5);
5543 ip += 5;
5544 need_merge = 1;
5545 break;
5547 case CEE_SWITCH: {
5548 guint32 entries;
5549 code_bounds_check (5);
5550 entries = read32 (ip + 1);
5552 if (entries > 0xFFFFFFFFU / sizeof (guint32))
5553 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Too many switch entries %x at 0x%04x", entries, ctx.ip_offset));
5555 ip += 5;
5556 code_bounds_check (sizeof (guint32) * entries);
5558 do_switch (&ctx, entries, ip);
5559 ip += sizeof (guint32) * entries;
5560 break;
5562 case CEE_LDIND_I1:
5563 case CEE_LDIND_U1:
5564 case CEE_LDIND_I2:
5565 case CEE_LDIND_U2:
5566 case CEE_LDIND_I4:
5567 case CEE_LDIND_U4:
5568 case CEE_LDIND_I8:
5569 case CEE_LDIND_I:
5570 case CEE_LDIND_R4:
5571 case CEE_LDIND_R8:
5572 case CEE_LDIND_REF:
5573 do_load_indirect (&ctx, *ip);
5574 ++ip;
5575 break;
5577 case CEE_STIND_REF:
5578 case CEE_STIND_I1:
5579 case CEE_STIND_I2:
5580 case CEE_STIND_I4:
5581 case CEE_STIND_I8:
5582 case CEE_STIND_R4:
5583 case CEE_STIND_R8:
5584 case CEE_STIND_I:
5585 do_store_indirect (&ctx, *ip);
5586 ++ip;
5587 break;
5589 case CEE_NOT:
5590 case CEE_NEG:
5591 do_unary_math_op (&ctx, *ip);
5592 ++ip;
5593 break;
5595 case CEE_CONV_I1:
5596 case CEE_CONV_I2:
5597 case CEE_CONV_I4:
5598 case CEE_CONV_U1:
5599 case CEE_CONV_U2:
5600 case CEE_CONV_U4:
5601 do_conversion (&ctx, TYPE_I4);
5602 ++ip;
5603 break;
5605 case CEE_CONV_I8:
5606 case CEE_CONV_U8:
5607 do_conversion (&ctx, TYPE_I8);
5608 ++ip;
5609 break;
5611 case CEE_CONV_R4:
5612 case CEE_CONV_R8:
5613 case CEE_CONV_R_UN:
5614 do_conversion (&ctx, TYPE_R8);
5615 ++ip;
5616 break;
5618 case CEE_CONV_I:
5619 case CEE_CONV_U:
5620 do_conversion (&ctx, TYPE_NATIVE_INT);
5621 ++ip;
5622 break;
5624 case CEE_CPOBJ:
5625 code_bounds_check (5);
5626 do_cpobj (&ctx, read32 (ip + 1));
5627 ip += 5;
5628 break;
5630 case CEE_LDOBJ:
5631 code_bounds_check (5);
5632 do_ldobj_value (&ctx, read32 (ip + 1));
5633 ip += 5;
5634 break;
5636 case CEE_LDSTR:
5637 code_bounds_check (5);
5638 do_ldstr (&ctx, read32 (ip + 1));
5639 ip += 5;
5640 break;
5642 case CEE_NEWOBJ:
5643 code_bounds_check (5);
5644 do_newobj (&ctx, read32 (ip + 1));
5645 ip += 5;
5646 break;
5648 case CEE_CASTCLASS:
5649 case CEE_ISINST:
5650 code_bounds_check (5);
5651 do_cast (&ctx, read32 (ip + 1), *ip == CEE_CASTCLASS ? "castclass" : "isinst");
5652 ip += 5;
5653 break;
5655 case CEE_UNUSED58:
5656 case CEE_UNUSED1:
5657 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5658 ++ip;
5659 break;
5661 case CEE_UNBOX:
5662 code_bounds_check (5);
5663 do_unbox_value (&ctx, read32 (ip + 1));
5664 ip += 5;
5665 break;
5667 case CEE_THROW:
5668 do_throw (&ctx);
5669 start = 1;
5670 ++ip;
5671 break;
5673 case CEE_LDFLD:
5674 case CEE_LDFLDA:
5675 code_bounds_check (5);
5676 do_push_field (&ctx, read32 (ip + 1), *ip == CEE_LDFLDA);
5677 ip += 5;
5678 break;
5680 case CEE_LDSFLD:
5681 case CEE_LDSFLDA:
5682 code_bounds_check (5);
5683 do_push_static_field (&ctx, read32 (ip + 1), *ip == CEE_LDSFLDA);
5684 ip += 5;
5685 break;
5687 case CEE_STFLD:
5688 code_bounds_check (5);
5689 do_store_field (&ctx, read32 (ip + 1));
5690 ip += 5;
5691 break;
5693 case CEE_STSFLD:
5694 code_bounds_check (5);
5695 do_store_static_field (&ctx, read32 (ip + 1));
5696 ip += 5;
5697 break;
5699 case CEE_STOBJ:
5700 code_bounds_check (5);
5701 do_stobj (&ctx, read32 (ip + 1));
5702 ip += 5;
5703 break;
5705 case CEE_CONV_OVF_I1_UN:
5706 case CEE_CONV_OVF_I2_UN:
5707 case CEE_CONV_OVF_I4_UN:
5708 case CEE_CONV_OVF_U1_UN:
5709 case CEE_CONV_OVF_U2_UN:
5710 case CEE_CONV_OVF_U4_UN:
5711 do_conversion (&ctx, TYPE_I4);
5712 ++ip;
5713 break;
5715 case CEE_CONV_OVF_I8_UN:
5716 case CEE_CONV_OVF_U8_UN:
5717 do_conversion (&ctx, TYPE_I8);
5718 ++ip;
5719 break;
5721 case CEE_CONV_OVF_I_UN:
5722 case CEE_CONV_OVF_U_UN:
5723 do_conversion (&ctx, TYPE_NATIVE_INT);
5724 ++ip;
5725 break;
5727 case CEE_BOX:
5728 code_bounds_check (5);
5729 do_box_value (&ctx, read32 (ip + 1));
5730 ip += 5;
5731 break;
5733 case CEE_NEWARR:
5734 code_bounds_check (5);
5735 do_newarr (&ctx, read32 (ip + 1));
5736 ip += 5;
5737 break;
5739 case CEE_LDLEN:
5740 do_ldlen (&ctx);
5741 ++ip;
5742 break;
5744 case CEE_LDELEMA:
5745 code_bounds_check (5);
5746 do_ldelema (&ctx, read32 (ip + 1));
5747 ip += 5;
5748 break;
5750 case CEE_LDELEM_I1:
5751 case CEE_LDELEM_U1:
5752 case CEE_LDELEM_I2:
5753 case CEE_LDELEM_U2:
5754 case CEE_LDELEM_I4:
5755 case CEE_LDELEM_U4:
5756 case CEE_LDELEM_I8:
5757 case CEE_LDELEM_I:
5758 case CEE_LDELEM_R4:
5759 case CEE_LDELEM_R8:
5760 case CEE_LDELEM_REF:
5761 do_ldelem (&ctx, *ip, 0);
5762 ++ip;
5763 break;
5765 case CEE_STELEM_I:
5766 case CEE_STELEM_I1:
5767 case CEE_STELEM_I2:
5768 case CEE_STELEM_I4:
5769 case CEE_STELEM_I8:
5770 case CEE_STELEM_R4:
5771 case CEE_STELEM_R8:
5772 case CEE_STELEM_REF:
5773 do_stelem (&ctx, *ip, 0);
5774 ++ip;
5775 break;
5777 case CEE_LDELEM:
5778 code_bounds_check (5);
5779 do_ldelem (&ctx, *ip, read32 (ip + 1));
5780 ip += 5;
5781 break;
5783 case CEE_STELEM:
5784 code_bounds_check (5);
5785 do_stelem (&ctx, *ip, read32 (ip + 1));
5786 ip += 5;
5787 break;
5789 case CEE_UNBOX_ANY:
5790 code_bounds_check (5);
5791 do_unbox_any (&ctx, read32 (ip + 1));
5792 ip += 5;
5793 break;
5795 case CEE_CONV_OVF_I1:
5796 case CEE_CONV_OVF_U1:
5797 case CEE_CONV_OVF_I2:
5798 case CEE_CONV_OVF_U2:
5799 case CEE_CONV_OVF_I4:
5800 case CEE_CONV_OVF_U4:
5801 do_conversion (&ctx, TYPE_I4);
5802 ++ip;
5803 break;
5805 case CEE_CONV_OVF_I8:
5806 case CEE_CONV_OVF_U8:
5807 do_conversion (&ctx, TYPE_I8);
5808 ++ip;
5809 break;
5811 case CEE_CONV_OVF_I:
5812 case CEE_CONV_OVF_U:
5813 do_conversion (&ctx, TYPE_NATIVE_INT);
5814 ++ip;
5815 break;
5817 case CEE_REFANYVAL:
5818 code_bounds_check (5);
5819 do_refanyval (&ctx, read32 (ip + 1));
5820 ip += 5;
5821 break;
5823 case CEE_CKFINITE:
5824 do_ckfinite (&ctx);
5825 ++ip;
5826 break;
5828 case CEE_MKREFANY:
5829 code_bounds_check (5);
5830 do_mkrefany (&ctx, read32 (ip + 1));
5831 ip += 5;
5832 break;
5834 case CEE_LDTOKEN:
5835 code_bounds_check (5);
5836 do_load_token (&ctx, read32 (ip + 1));
5837 ip += 5;
5838 break;
5840 case CEE_ENDFINALLY:
5841 if (!is_correct_endfinally (ctx.header, ip_offset))
5842 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("endfinally must be used inside a finally/fault handler at 0x%04x", ctx.ip_offset));
5843 ctx.eval.size = 0;
5844 start = 1;
5845 ++ip;
5846 break;
5848 case CEE_LEAVE:
5849 code_bounds_check (5);
5850 do_leave (&ctx, read32 (ip + 1) + 5);
5851 ip += 5;
5852 start = 1;
5853 need_merge = 1;
5854 break;
5856 case CEE_LEAVE_S:
5857 code_bounds_check (2);
5858 do_leave (&ctx, (signed char)ip [1] + 2);
5859 ip += 2;
5860 start = 1;
5861 need_merge = 1;
5862 break;
5864 case CEE_PREFIX1:
5865 code_bounds_check (2);
5866 ++ip;
5867 switch (*ip) {
5868 case CEE_STLOC:
5869 code_bounds_check (3);
5870 store_local (&ctx, read16 (ip + 1));
5871 ip += 3;
5872 break;
5874 case CEE_CEQ:
5875 do_cmp_op (&ctx, cmp_br_eq_op, *ip);
5876 ++ip;
5877 break;
5879 case CEE_CGT:
5880 case CEE_CGT_UN:
5881 case CEE_CLT:
5882 case CEE_CLT_UN:
5883 do_cmp_op (&ctx, cmp_br_op, *ip);
5884 ++ip;
5885 break;
5887 case CEE_STARG:
5888 code_bounds_check (3);
5889 store_arg (&ctx, read16 (ip + 1) );
5890 ip += 3;
5891 break;
5894 case CEE_ARGLIST:
5895 if (!check_overflow (&ctx))
5896 break;
5897 if (ctx.signature->call_convention != MONO_CALL_VARARG)
5898 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot use arglist on method without VARGARG calling convention at 0x%04x", ctx.ip_offset));
5899 set_stack_value (&ctx, stack_push (&ctx), m_class_get_byval_arg (mono_defaults.argumenthandle_class), FALSE);
5900 ++ip;
5901 break;
5903 case CEE_LDFTN:
5904 code_bounds_check (5);
5905 do_load_function_ptr (&ctx, read32 (ip + 1), FALSE);
5906 ip += 5;
5907 break;
5909 case CEE_LDVIRTFTN:
5910 code_bounds_check (5);
5911 do_load_function_ptr (&ctx, read32 (ip + 1), TRUE);
5912 ip += 5;
5913 break;
5915 case CEE_LDARG:
5916 case CEE_LDARGA:
5917 code_bounds_check (3);
5918 push_arg (&ctx, read16 (ip + 1), *ip == CEE_LDARGA);
5919 ip += 3;
5920 break;
5922 case CEE_LDLOC:
5923 case CEE_LDLOCA:
5924 code_bounds_check (3);
5925 push_local (&ctx, read16 (ip + 1), *ip == CEE_LDLOCA);
5926 ip += 3;
5927 break;
5929 case CEE_LOCALLOC:
5930 do_localloc (&ctx);
5931 ++ip;
5932 break;
5934 case CEE_UNUSED56:
5935 case CEE_UNUSED57:
5936 case CEE_UNUSED70:
5937 case CEE_UNUSED:
5938 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5939 ++ip;
5940 break;
5941 case CEE_ENDFILTER:
5942 do_endfilter (&ctx);
5943 start = 1;
5944 ++ip;
5945 break;
5946 case CEE_UNALIGNED_:
5947 code_bounds_check (2);
5948 prefix |= PREFIX_UNALIGNED;
5949 ip += 2;
5950 break;
5951 case CEE_VOLATILE_:
5952 prefix |= PREFIX_VOLATILE;
5953 ++ip;
5954 break;
5955 case CEE_TAIL_:
5956 prefix |= PREFIX_TAIL;
5957 ++ip;
5958 if (ip < end && (*ip != CEE_CALL && *ip != CEE_CALLI && *ip != CEE_CALLVIRT))
5959 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("tail prefix must be used only with call opcodes at 0x%04x", ip_offset));
5960 break;
5962 case CEE_INITOBJ:
5963 code_bounds_check (5);
5964 do_initobj (&ctx, read32 (ip + 1));
5965 ip += 5;
5966 break;
5968 case CEE_CONSTRAINED_:
5969 code_bounds_check (5);
5970 ctx.constrained_type = get_boxable_mono_type (&ctx, read32 (ip + 1), "constrained.");
5971 prefix |= PREFIX_CONSTRAINED;
5972 ip += 5;
5973 break;
5975 case CEE_READONLY_:
5976 prefix |= PREFIX_READONLY;
5977 ip++;
5978 break;
5980 case CEE_CPBLK:
5981 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5982 if (!check_underflow (&ctx, 3))
5983 break;
5984 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction cpblk is not verifiable at 0x%04x", ctx.ip_offset));
5985 ip++;
5986 break;
5988 case CEE_INITBLK:
5989 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5990 if (!check_underflow (&ctx, 3))
5991 break;
5992 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction initblk is not verifiable at 0x%04x", ctx.ip_offset));
5993 ip++;
5994 break;
5996 case CEE_NO_:
5997 ip += 2;
5998 break;
5999 case CEE_RETHROW:
6000 if (!is_correct_rethrow (ctx.header, ip_offset))
6001 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("rethrow must be used inside a catch handler at 0x%04x", ctx.ip_offset));
6002 ctx.eval.size = 0;
6003 start = 1;
6004 ++ip;
6005 break;
6007 case CEE_SIZEOF:
6008 code_bounds_check (5);
6009 do_sizeof (&ctx, read32 (ip + 1));
6010 ip += 5;
6011 break;
6013 case CEE_REFANYTYPE:
6014 do_refanytype (&ctx);
6015 ++ip;
6016 break;
6018 default:
6019 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction FE %x at 0x%04x", *ip, ctx.ip_offset));
6020 ++ip;
6022 break;
6024 default:
6025 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ctx.ip_offset));
6026 ++ip;
6029 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
6030 if (prefix) {
6031 if (!ctx.prefix_set) //first prefix
6032 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
6033 ctx.prefix_set |= prefix;
6034 ctx.has_flags = TRUE;
6035 prefix = 0;
6036 } else {
6037 if (!ctx.has_flags)
6038 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
6040 if (ctx.prefix_set & PREFIX_CONSTRAINED)
6041 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after constrained prefix at 0x%04x", ctx.ip_offset));
6042 if (ctx.prefix_set & PREFIX_READONLY)
6043 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after readonly prefix at 0x%04x", ctx.ip_offset));
6044 if (ctx.prefix_set & PREFIX_VOLATILE)
6045 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after volatile prefix at 0x%04x", ctx.ip_offset));
6046 if (ctx.prefix_set & PREFIX_UNALIGNED)
6047 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after unaligned prefix at 0x%04x", ctx.ip_offset));
6048 ctx.prefix_set = prefix = 0;
6049 ctx.has_flags = FALSE;
6053 * if ip != end we overflowed: mark as error.
6055 if ((ip != end || !start) && ctx.verifiable && !ctx.list) {
6056 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Run ahead of method code at 0x%04x", ip_offset));
6059 /*We should guard against the last decoded opcode, otherwise we might add errors that doesn't make sense.*/
6060 for (i = 0; i < ctx.code_size && i < ip_offset; ++i) {
6061 if (ctx.code [i].flags & IL_CODE_FLAG_WAS_TARGET) {
6062 if (!(ctx.code [i].flags & IL_CODE_FLAG_SEEN))
6063 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or exception block target middle of instruction at 0x%04x", i));
6065 if (ctx.code [i].flags & IL_CODE_DELEGATE_SEQUENCE)
6066 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Branch to delegate code sequence at 0x%04x", i));
6068 if ((ctx.code [i].flags & IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL) && ctx.has_this_store)
6069 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at 0x%04x", i));
6071 if ((ctx.code [i].flags & IL_CODE_CALL_NONFINAL_VIRTUAL) && ctx.has_this_store)
6072 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));
6075 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) {
6076 char *method_name = mono_method_full_name (ctx.method, TRUE);
6077 char *type = mono_type_get_full_name (ctx.method->klass);
6078 if (m_class_get_parent (ctx.method->klass) && mono_class_has_failure (m_class_get_parent (ctx.method->klass)))
6079 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));
6080 else
6081 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Constructor %s for type %s not calling base type ctor.", method_name, type));
6082 g_free (method_name);
6083 g_free (type);
6086 cleanup:
6087 if (ctx.code) {
6088 for (i = 0; i < ctx.header->code_size; ++i) {
6089 if (ctx.code [i].stack)
6090 g_free (ctx.code [i].stack);
6094 for (tmp = ctx.funptrs; tmp; tmp = tmp->next)
6095 g_free (tmp->data);
6096 g_slist_free (ctx.funptrs);
6098 for (tmp = ctx.exception_types; tmp; tmp = tmp->next)
6099 mono_metadata_free_type ((MonoType *)tmp->data);
6100 g_slist_free (ctx.exception_types);
6102 for (i = 0; i < ctx.num_locals; ++i) {
6103 if (ctx.locals [i])
6104 mono_metadata_free_type (ctx.locals [i]);
6106 for (i = 0; i < ctx.max_args; ++i) {
6107 if (ctx.params [i])
6108 mono_metadata_free_type (ctx.params [i]);
6111 if (ctx.eval.stack)
6112 g_free (ctx.eval.stack);
6113 if (ctx.code)
6114 g_free (ctx.code);
6115 g_free (ctx.locals);
6116 g_free (ctx.locals_verification_state);
6117 g_free (ctx.params);
6118 mono_basic_block_free (original_bb);
6119 mono_metadata_free_mh (ctx.header);
6121 finish_collect_stats ();
6122 return ctx.list;
6125 char*
6126 mono_verify_corlib ()
6128 /* This is a public API function so cannot be removed */
6129 return NULL;
6133 * mono_verifier_is_enabled_for_method:
6134 * \param method the method to probe
6135 * \returns TRUE if \p method needs to be verified.
6137 gboolean
6138 mono_verifier_is_enabled_for_method (MonoMethod *method)
6140 return mono_verifier_is_enabled_for_class (method->klass) && (method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD);
6144 * mono_verifier_is_enabled_for_class:
6145 * \param klass The \c MonoClass to probe
6146 * \returns TRUE if \p klass need to be verified.
6148 gboolean
6149 mono_verifier_is_enabled_for_class (MonoClass *klass)
6151 MonoImage *image = m_class_get_image (klass);
6152 return verify_all || (verifier_mode > MONO_VERIFIER_MODE_OFF && !(image->assembly && image->assembly->in_gac) && image != mono_defaults.corlib);
6155 gboolean
6156 mono_verifier_is_enabled_for_image (MonoImage *image)
6158 return verify_all || verifier_mode > MONO_VERIFIER_MODE_OFF;
6162 * Dynamic methods are not considered full trust since if the user is trusted and need to
6163 * generate unsafe code, make the method skip verification - this is a known good way to do it.
6165 gboolean
6166 mono_verifier_is_method_full_trust (MonoMethod *method)
6168 return mono_verifier_is_class_full_trust (method->klass) && !method_is_dynamic (method);
6172 * Returns if @klass is under full trust or not.
6174 * TODO This code doesn't take CAS into account.
6176 * Under verify_all all user code must be verifiable if no security option was set
6179 gboolean
6180 mono_verifier_is_class_full_trust (MonoClass *klass)
6182 MonoImage *image = m_class_get_image (klass);
6183 /* under CoreCLR code is trusted if it is part of the "platform" otherwise all code inside the GAC is trusted */
6184 gboolean trusted_location = !mono_security_core_clr_enabled () ?
6185 (image->assembly && image->assembly->in_gac) : mono_security_core_clr_is_platform_image (image);
6187 if (verify_all && verifier_mode == MONO_VERIFIER_MODE_OFF)
6188 return trusted_location || image == mono_defaults.corlib;
6189 return verifier_mode < MONO_VERIFIER_MODE_VERIFIABLE || trusted_location || image == mono_defaults.corlib;
6192 GSList*
6193 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility, gboolean is_fulltrust)
6195 return mono_method_verify (method,
6196 (verifier_mode != MONO_VERIFIER_MODE_STRICT ? MONO_VERIFY_NON_STRICT: 0)
6197 | (!is_fulltrust && !mono_verifier_is_method_full_trust (method) ? MONO_VERIFY_FAIL_FAST : 0)
6198 | (skip_visibility ? MONO_VERIFY_SKIP_VISIBILITY : 0));
6201 static int
6202 get_field_end (MonoClassField *field)
6204 int align;
6205 int size = mono_type_size (field->type, &align);
6206 if (size == 0)
6207 size = 4; /*FIXME Is this a safe bet?*/
6208 return size + field->offset;
6211 static gboolean
6212 verify_class_for_overlapping_reference_fields (MonoClass *klass)
6214 int i = 0, j;
6215 gpointer iter = NULL;
6216 MonoClassField *field;
6217 gboolean is_fulltrust = mono_verifier_is_class_full_trust (klass);
6218 /*We can't skip types with !has_references since this is calculated after we have run.*/
6219 if (!mono_class_is_explicit_layout (klass))
6220 return TRUE;
6223 /*We must check for stuff overlapping reference fields.
6224 The outer loop uses mono_class_get_fields to ensure that MonoClass:fields get inited.
6226 while ((field = mono_class_get_fields (klass, &iter))) {
6227 int fieldEnd = get_field_end (field);
6228 gboolean is_valuetype = !MONO_TYPE_IS_REFERENCE (field->type);
6229 ++i;
6231 if (mono_field_is_deleted (field) || (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
6232 continue;
6234 int fcount = mono_class_get_field_count (klass);
6235 MonoClassField *klass_fields = m_class_get_fields (klass);
6236 for (j = i; j < fcount; ++j) {
6237 MonoClassField *other = &klass_fields [j];
6238 int otherEnd = get_field_end (other);
6239 if (mono_field_is_deleted (other) || (is_valuetype && !MONO_TYPE_IS_REFERENCE (other->type)) || (other->type->attrs & FIELD_ATTRIBUTE_STATIC))
6240 continue;
6242 if (!is_valuetype && MONO_TYPE_IS_REFERENCE (other->type) && field->offset == other->offset && is_fulltrust)
6243 continue;
6245 if ((otherEnd > field->offset && otherEnd <= fieldEnd) || (other->offset >= field->offset && other->offset < fieldEnd))
6246 return FALSE;
6249 return TRUE;
6252 static guint
6253 field_hash (gconstpointer key)
6255 const MonoClassField *field = (const MonoClassField *)key;
6256 return g_str_hash (field->name) ^ mono_metadata_type_hash (field->type); /**/
6259 static gboolean
6260 field_equals (gconstpointer _a, gconstpointer _b)
6262 const MonoClassField *a = (const MonoClassField *)_a;
6263 const MonoClassField *b = (const MonoClassField *)_b;
6264 return !strcmp (a->name, b->name) && mono_metadata_type_equal (a->type, b->type);
6268 static gboolean
6269 verify_class_fields (MonoClass *klass)
6271 gpointer iter = NULL;
6272 MonoClassField *field;
6273 MonoGenericContext *context = mono_class_get_context (klass);
6274 GHashTable *unique_fields = g_hash_table_new_full (&field_hash, &field_equals, NULL, NULL);
6275 if (mono_class_is_gtd (klass))
6276 context = &mono_class_get_generic_container (klass)->context;
6278 while ((field = mono_class_get_fields (klass, &iter)) != NULL) {
6279 if (!mono_type_is_valid_type_in_context (field->type, context)) {
6280 g_hash_table_destroy (unique_fields);
6281 return FALSE;
6283 if (g_hash_table_lookup (unique_fields, field)) {
6284 g_hash_table_destroy (unique_fields);
6285 return FALSE;
6287 g_hash_table_insert (unique_fields, field, field);
6289 g_hash_table_destroy (unique_fields);
6290 return TRUE;
6293 static gboolean
6294 verify_interfaces (MonoClass *klass)
6296 int i;
6297 guint16 klass_interface_count = m_class_get_interface_count (klass);
6298 MonoClass **klass_interfaces = m_class_get_interfaces (klass);
6299 for (i = 0; i < klass_interface_count; ++i) {
6300 MonoClass *iface = klass_interfaces [i];
6301 if (!mono_class_get_flags (iface))
6302 return FALSE;
6304 return TRUE;
6307 static gboolean
6308 verify_valuetype_layout_with_target (MonoClass *klass, MonoClass *target_class)
6310 int type;
6311 gpointer iter = NULL;
6312 MonoClassField *field;
6313 MonoClass *field_class;
6315 if (!m_class_is_valuetype (klass))
6316 return TRUE;
6318 type = m_class_get_byval_arg (klass)->type;
6319 /*primitive type fields are not properly decoded*/
6320 if ((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_R8) || (type >= MONO_TYPE_I && type <= MONO_TYPE_U))
6321 return TRUE;
6323 while ((field = mono_class_get_fields (klass, &iter)) != NULL) {
6324 if (!field->type)
6325 return FALSE;
6327 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
6328 continue;
6330 field_class = mono_class_get_generic_type_definition (mono_class_from_mono_type (field->type));
6332 if (field_class == target_class || klass == field_class || !verify_valuetype_layout_with_target (field_class, target_class))
6333 return FALSE;
6336 return TRUE;
6339 static gboolean
6340 verify_valuetype_layout (MonoClass *klass)
6342 gboolean res;
6343 res = verify_valuetype_layout_with_target (klass, klass);
6344 return res;
6347 static gboolean
6348 recursive_mark_constraint_args (MonoBitSet *used_args, MonoGenericContainer *gc, MonoType *type)
6350 int idx;
6351 MonoClass **constraints;
6352 MonoGenericParamInfo *param_info;
6354 g_assert (mono_type_is_generic_argument (type));
6356 idx = mono_type_get_generic_param_num (type);
6357 if (mono_bitset_test_fast (used_args, idx))
6358 return FALSE;
6360 mono_bitset_set_fast (used_args, idx);
6361 param_info = mono_generic_container_get_param_info (gc, idx);
6363 if (!param_info->constraints)
6364 return TRUE;
6366 for (constraints = param_info->constraints; *constraints; ++constraints) {
6367 MonoClass *ctr = *constraints;
6368 MonoType *constraint_type = m_class_get_byval_arg (ctr);
6370 if (mono_type_is_generic_argument (constraint_type) && !recursive_mark_constraint_args (used_args, gc, constraint_type))
6371 return FALSE;
6373 return TRUE;
6376 static gboolean
6377 verify_generic_parameters (MonoClass *klass)
6379 int i;
6380 MonoGenericContainer *gc = mono_class_get_generic_container (klass);
6381 MonoBitSet *used_args = mono_bitset_new (gc->type_argc, 0);
6383 for (i = 0; i < gc->type_argc; ++i) {
6384 MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
6385 MonoClass **constraints;
6387 if (!param_info->constraints)
6388 continue;
6390 mono_bitset_clear_all (used_args);
6391 mono_bitset_set_fast (used_args, i);
6393 for (constraints = param_info->constraints; *constraints; ++constraints) {
6394 MonoClass *ctr = *constraints;
6395 MonoType *constraint_type = m_class_get_byval_arg (ctr);
6397 if (!mono_class_can_access_class (klass, ctr))
6398 goto fail;
6400 if (!mono_type_is_valid_type_in_context (constraint_type, &gc->context))
6401 goto fail;
6403 if (mono_type_is_generic_argument (constraint_type) && !recursive_mark_constraint_args (used_args, gc, constraint_type))
6404 goto fail;
6405 if (mono_class_is_ginst (ctr) && !mono_class_is_valid_generic_instantiation (NULL, ctr))
6406 goto fail;
6409 mono_bitset_free (used_args);
6410 return TRUE;
6412 fail:
6413 mono_bitset_free (used_args);
6414 return FALSE;
6418 * Check if the class is verifiable.
6420 * Right now there are no conditions that make a class a valid but not verifiable. Both overlapping reference
6421 * field and invalid generic instantiation are fatal errors.
6423 * This method must be safe to be called from mono_class_init and all code must be carefull about that.
6426 gboolean
6427 mono_verifier_verify_class (MonoClass *klass)
6429 MonoClass *klass_parent = m_class_get_parent (klass);
6430 /*Neither <Module>, object or ifaces have parent.*/
6431 if (!klass_parent &&
6432 klass != mono_defaults.object_class &&
6433 !MONO_CLASS_IS_INTERFACE (klass) &&
6434 (!image_is_dynamic (m_class_get_image (klass)) && m_class_get_type_token (klass) != 0x2000001)) /*<Module> is the first type in the assembly*/
6435 return FALSE;
6436 if (m_class_get_parent (klass)) {
6437 if (MONO_CLASS_IS_INTERFACE (klass_parent))
6438 return FALSE;
6439 if (!mono_class_is_ginst (klass) && mono_class_is_gtd (klass_parent))
6440 return FALSE;
6441 if (mono_class_is_ginst (klass_parent) && !mono_class_is_ginst (klass)) {
6442 MonoGenericContext *context = mono_class_get_context (klass);
6443 if (mono_class_is_gtd (klass))
6444 context = &mono_class_get_generic_container (klass)->context;
6445 if (!mono_type_is_valid_type_in_context (m_class_get_byval_arg (klass_parent), context))
6446 return FALSE;
6449 if (mono_class_is_gtd (klass) && (mono_class_is_explicit_layout (klass)))
6450 return FALSE;
6451 if (mono_class_is_gtd (klass) && !verify_generic_parameters (klass))
6452 return FALSE;
6453 if (!verify_class_for_overlapping_reference_fields (klass))
6454 return FALSE;
6455 if (mono_class_is_ginst (klass) && !mono_class_is_valid_generic_instantiation (NULL, klass))
6456 return FALSE;
6457 if (!mono_class_is_ginst (klass) && !verify_class_fields (klass))
6458 return FALSE;
6459 if (m_class_is_valuetype (klass) && !verify_valuetype_layout (klass))
6460 return FALSE;
6461 if (!verify_interfaces (klass))
6462 return FALSE;
6463 return TRUE;
6466 gboolean
6467 mono_verifier_class_is_valid_generic_instantiation (MonoClass *klass)
6469 return mono_class_is_valid_generic_instantiation (NULL, klass);
6472 gboolean
6473 mono_verifier_is_method_valid_generic_instantiation (MonoMethod *method)
6475 if (!method->is_inflated)
6476 return TRUE;
6477 return mono_method_is_valid_generic_instantiation (NULL, method);
6480 #else
6482 gboolean
6483 mono_verifier_verify_class (MonoClass *klass)
6485 /* The verifier was disabled at compile time */
6486 return TRUE;
6489 GSList*
6490 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility, gboolean is_fulltrust)
6492 /* The verifier was disabled at compile time */
6493 return NULL;
6496 gboolean
6497 mono_verifier_is_class_full_trust (MonoClass *klass)
6499 /* The verifier was disabled at compile time */
6500 return TRUE;
6503 gboolean
6504 mono_verifier_is_method_full_trust (MonoMethod *method)
6506 /* The verifier was disabled at compile time */
6507 return TRUE;
6510 gboolean
6511 mono_verifier_is_enabled_for_image (MonoImage *image)
6513 /* The verifier was disabled at compile time */
6514 return FALSE;
6517 gboolean
6518 mono_verifier_is_enabled_for_class (MonoClass *klass)
6520 /* The verifier was disabled at compile time */
6521 return FALSE;
6524 gboolean
6525 mono_verifier_is_enabled_for_method (MonoMethod *method)
6527 /* The verifier was disabled at compile time */
6528 return FALSE;
6531 GSList*
6532 mono_method_verify (MonoMethod *method, int level)
6534 /* The verifier was disabled at compile time */
6535 return NULL;
6538 void
6539 mono_free_verify_list (GSList *list)
6541 /* The verifier was disabled at compile time */
6542 /* will always be null if verifier is disabled */
6545 gboolean
6546 mono_verifier_class_is_valid_generic_instantiation (MonoClass *klass)
6548 return TRUE;
6551 gboolean
6552 mono_verifier_is_method_valid_generic_instantiation (MonoMethod *method)
6554 return TRUE;
6559 #endif