2009-09-15 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / verify.c
1 /*
2  * verify.c: 
3  *
4  * Author:
5  *      Mono Project (http://www.mono-project.com)
6  *
7  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9  */
10 #include <config.h>
11
12 #include <mono/metadata/object-internals.h>
13 #include <mono/metadata/verify.h>
14 #include <mono/metadata/verify-internals.h>
15 #include <mono/metadata/opcodes.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/reflection.h>
18 #include <mono/metadata/debug-helpers.h>
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/metadata.h>
21 #include <mono/metadata/metadata-internals.h>
22 #include <mono/metadata/class-internals.h>
23 #include <mono/metadata/security-manager.h>
24 #include <mono/metadata/security-core-clr.h>
25 #include <mono/metadata/tokentype.h>
26 #include <string.h>
27 #include <signal.h>
28 #include <ctype.h>
29
30
31 static MiniVerifierMode verifier_mode = MONO_VERIFIER_MODE_OFF;
32 static gboolean verify_all = FALSE;
33
34 /*
35  * Set the desired level of checks for the verfier.
36  * 
37  */
38 void
39 mono_verifier_set_mode (MiniVerifierMode mode)
40 {
41         verifier_mode = mode;
42 }
43
44 void
45 mono_verifier_enable_verify_all ()
46 {
47         verify_all = TRUE;
48 }
49
50 #ifndef DISABLE_VERIFIER
51 /*
52  * Pull the list of opcodes
53  */
54 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
55         a = i,
56
57 enum {
58 #include "mono/cil/opcode.def"
59         LAST = 0xff
60 };
61 #undef OPDEF
62
63 #ifdef MONO_VERIFIER_DEBUG
64 #define VERIFIER_DEBUG(code) do { code } while (0)
65 #else
66 #define VERIFIER_DEBUG(code)
67 #endif
68
69 //////////////////////////////////////////////////////////////////
70 #define IS_STRICT_MODE(ctx) (((ctx)->level & MONO_VERIFY_NON_STRICT) == 0)
71 #define IS_FAIL_FAST_MODE(ctx) (((ctx)->level & MONO_VERIFY_FAIL_FAST) == MONO_VERIFY_FAIL_FAST)
72 #define IS_SKIP_VISIBILITY(ctx) (((ctx)->level & MONO_VERIFY_SKIP_VISIBILITY) == MONO_VERIFY_SKIP_VISIBILITY)
73 #define IS_REPORT_ALL_ERRORS(ctx) (((ctx)->level & MONO_VERIFY_REPORT_ALL_ERRORS) == MONO_VERIFY_REPORT_ALL_ERRORS)
74 #define CLEAR_PREFIX(ctx, prefix) do { (ctx)->prefix_set &= ~(prefix); } while (0)
75 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception)    \
76         do {    \
77                 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1);      \
78                 vinfo->info.status = __status;  \
79                 vinfo->info.message = ( __msg );        \
80                 vinfo->exception_type = (__exception);  \
81                 (__ctx)->list = g_slist_prepend ((__ctx)->list, vinfo); \
82         } while (0)
83
84 //TODO support MONO_VERIFY_REPORT_ALL_ERRORS
85 #define ADD_VERIFY_ERROR(__ctx, __msg)  \
86         do {    \
87                 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
88                 (__ctx)->valid = 0; \
89         } while (0)
90
91 #define CODE_NOT_VERIFIABLE(__ctx, __msg) \
92         do {    \
93                 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
94                         ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, MONO_EXCEPTION_UNVERIFIABLE_IL); \
95                         (__ctx)->verifiable = 0; \
96                         if (IS_FAIL_FAST_MODE (__ctx)) \
97                                 (__ctx)->valid = 0; \
98                 } \
99         } while (0)
100
101 #define ADD_VERIFY_ERROR2(__ctx, __msg, __exception)    \
102         do {    \
103                 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, __exception); \
104                 (__ctx)->valid = 0; \
105         } while (0)
106
107 #define CODE_NOT_VERIFIABLE2(__ctx, __msg, __exception) \
108         do {    \
109                 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
110                         ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, __exception); \
111                         (__ctx)->verifiable = 0; \
112                         if (IS_FAIL_FAST_MODE (__ctx)) \
113                                 (__ctx)->valid = 0; \
114                 } \
115         } while (0)
116 /*Flags to be used with ILCodeDesc::flags */
117 enum {
118         /*Instruction has not been processed.*/
119         IL_CODE_FLAG_NOT_PROCESSED  = 0,
120         /*Instruction was decoded by mono_method_verify loop.*/
121         IL_CODE_FLAG_SEEN = 1,
122         /*Instruction was target of a branch or is at a protected block boundary.*/
123         IL_CODE_FLAG_WAS_TARGET = 2,
124         /*Used by stack_init to avoid double initialize each entry.*/
125         IL_CODE_FLAG_STACK_INITED = 4,
126         /*Used by merge_stacks to decide if it should just copy the eval stack.*/
127         IL_CODE_STACK_MERGED = 8,
128         /*This instruction is part of the delegate construction sequence, it cannot be target of a branch.*/
129         IL_CODE_DELEGATE_SEQUENCE = 0x10,
130         /*This is a delegate created from a ldftn to a non final virtual method*/
131         IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL = 0x20,
132         /*This is a call to a non final virtual method*/
133         IL_CODE_CALL_NONFINAL_VIRTUAL = 0x40,
134 };
135
136 typedef enum {
137         RESULT_VALID,
138         RESULT_UNVERIFIABLE,
139         RESULT_INVALID
140 } verify_result_t;
141
142 typedef struct {
143         MonoType *type;
144         int stype;
145         MonoMethod *method;
146 } ILStackDesc;
147
148
149 typedef struct {
150         ILStackDesc *stack;
151         guint16 size;
152         guint16 flags;
153 } ILCodeDesc;
154
155 typedef struct {
156         int max_args;
157         int max_stack;
158         int verifiable;
159         int valid;
160         int level;
161
162         int code_size;
163         ILCodeDesc *code;
164         ILCodeDesc eval;
165
166         MonoType **params;
167         GSList *list;
168         /*Allocated fnptr MonoType that should be freed by us.*/
169         GSList *funptrs;
170         /*Type dup'ed exception types from catch blocks.*/
171         GSList *exception_types;
172
173         int num_locals;
174         MonoType **locals;
175
176         /*TODO get rid of target here, need_merge in mono_method_verify and hoist the merging code in the branching code*/
177         int target;
178
179         guint32 ip_offset;
180         MonoMethodSignature *signature;
181         MonoMethodHeader *header;
182
183         MonoGenericContext *generic_context;
184         MonoImage *image;
185         MonoMethod *method;
186
187         /*This flag helps solving a corner case of delegate verification in that you cannot have a "starg 0" 
188          *on a method that creates a delegate for a non-final virtual method using ldftn*/
189         gboolean has_this_store;
190
191         /*This flag is used to control if the contructor of the parent class has been called.
192          *If the this pointer is pushed on the eval stack and it's a reference type constructor and
193          * super_ctor_called is false, the uninitialized flag is set on the pushed value.
194          * 
195          * Poping an uninitialized this ptr from the eval stack is an unverifiable operation unless
196          * the safe variant is used. Only a few opcodes can use it : dup, pop, ldfld, stfld and call to a constructor.
197          */
198         gboolean super_ctor_called;
199
200         guint32 prefix_set;
201         gboolean has_flags;
202         MonoType *constrained_type;
203 } VerifyContext;
204
205 static void
206 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external);
207
208 static int
209 get_stack_type (MonoType *type);
210
211 static gboolean
212 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn);
213
214 static gboolean
215 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass);
216
217 static gboolean
218 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method);
219 //////////////////////////////////////////////////////////////////
220
221
222
223 enum {
224         TYPE_INV = 0, /* leave at 0. */
225         TYPE_I4  = 1,
226         TYPE_I8  = 2,
227         TYPE_NATIVE_INT = 3,
228         TYPE_R8  = 4,
229         /* Used by operator tables to resolve pointer types (managed & unmanaged) and by unmanaged pointer types*/
230         TYPE_PTR  = 5,
231         /* value types and classes */
232         TYPE_COMPLEX = 6,
233         /* Number of types, used to define the size of the tables*/
234         TYPE_MAX = 6,
235
236         /* Used by tables to signal that a result is not verifiable*/
237         NON_VERIFIABLE_RESULT = 0x80,
238
239         /*Mask used to extract just the type, excluding flags */
240         TYPE_MASK = 0x0F,
241
242         /* The stack type is a managed pointer, unmask the value to res */
243         POINTER_MASK = 0x100,
244         
245         /*Stack type with the pointer mask*/
246         RAW_TYPE_MASK = 0x10F,
247
248         /* Controlled Mutability Manager Pointer */
249         CMMP_MASK = 0x200,
250
251         /* The stack type is a null literal*/
252         NULL_LITERAL_MASK = 0x400,
253         
254         /**Used by ldarg.0 and family to let delegate verification happens.*/
255         THIS_POINTER_MASK = 0x800,
256
257         /**Signals that this is a boxed value type*/
258         BOXED_MASK = 0x1000,
259
260         /*This is an unitialized this ref*/
261         UNINIT_THIS_MASK = 0x2000,
262 };
263
264 static const char* const
265 type_names [TYPE_MAX + 1] = {
266         "Invalid",
267         "Int32",
268         "Int64",
269         "Native Int",
270         "Float64",
271         "Native Pointer",
272         "Complex"       
273 };
274
275 enum {
276         PREFIX_UNALIGNED = 1,
277         PREFIX_VOLATILE  = 2,
278         PREFIX_TAIL      = 4,
279         PREFIX_CONSTRAINED = 8,
280         PREFIX_READONLY = 16
281 };
282 //////////////////////////////////////////////////////////////////
283
284
285 /*Token validation macros and functions */
286 #define IS_MEMBER_REF(token) (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
287 #define IS_METHOD_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
288 #define IS_METHOD_SPEC(token) (mono_metadata_token_table (token) == MONO_TABLE_METHODSPEC)
289 #define IS_FIELD_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_FIELD)
290
291 #define IS_TYPE_REF(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPEREF)
292 #define IS_TYPE_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPEDEF)
293 #define IS_TYPE_SPEC(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC)
294 #define IS_METHOD_DEF_OR_REF_OR_SPEC(token) (IS_METHOD_DEF (token) || IS_MEMBER_REF (token) || IS_METHOD_SPEC (token))
295 #define IS_TYPE_DEF_OR_REF_OR_SPEC(token) (IS_TYPE_DEF (token) || IS_TYPE_REF (token) || IS_TYPE_SPEC (token))
296 #define IS_FIELD_DEF_OR_REF(token) (IS_FIELD_DEF (token) || IS_MEMBER_REF (token))
297
298 /*
299  * Verify if @token refers to a valid row on int's table.
300  */
301 static gboolean
302 token_bounds_check (MonoImage *image, guint32 token)
303 {
304         if (image->dynamic)
305                 return mono_reflection_is_valid_dynamic_token ((MonoDynamicImage*)image, token);
306         return image->tables [mono_metadata_token_table (token)].rows >= mono_metadata_token_index (token);
307 }
308
309 static MonoType *
310 mono_type_create_fnptr_from_mono_method (VerifyContext *ctx, MonoMethod *method)
311 {
312         MonoType *res = g_new0 (MonoType, 1);
313         //FIXME use mono_method_get_signature_full
314         res->data.method = mono_method_signature (method);
315         res->type = MONO_TYPE_FNPTR;
316         ctx->funptrs = g_slist_prepend (ctx->funptrs, res);
317         return res;
318 }
319
320 /*
321  * mono_type_is_enum_type:
322  * 
323  * Returns TRUE if @type is an enum type. 
324  */
325 static gboolean
326 mono_type_is_enum_type (MonoType *type)
327 {
328         if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)
329                 return TRUE;
330         if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype)
331                 return TRUE;
332         return FALSE;
333 }
334
335 /*
336  * mono_type_is_value_type:
337  * 
338  * Returns TRUE if @type is named after @namespace.@name.
339  * 
340  */
341 static gboolean
342 mono_type_is_value_type (MonoType *type, const char *namespace, const char *name)
343 {
344         return type->type == MONO_TYPE_VALUETYPE &&
345                 !strcmp (namespace, type->data.klass->name_space) &&
346                 !strcmp (name, type->data.klass->name);
347 }
348
349 /*
350  * Returns TURE if @type is VAR or MVAR
351  */
352 static gboolean
353 mono_type_is_generic_argument (MonoType *type)
354 {
355         return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
356 }
357
358 /*
359  * mono_type_get_underlying_type_any:
360  * 
361  * This functions is just like mono_type_get_underlying_type but it doesn't care if the type is byref.
362  * 
363  * Returns the underlying type of @type regardless if it is byref or not.
364  */
365 static MonoType*
366 mono_type_get_underlying_type_any (MonoType *type)
367 {
368         if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)
369                 return mono_class_enum_basetype (type->data.klass);
370         if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype)
371                 return mono_class_enum_basetype (type->data.generic_class->container_class);
372         return type;
373 }
374
375 static const char*
376 mono_type_get_stack_name (MonoType *type)
377 {
378         return type_names [get_stack_type (type) & TYPE_MASK];
379 }
380
381 #define CTOR_REQUIRED_FLAGS (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_RT_SPECIAL_NAME)
382 #define CTOR_INVALID_FLAGS (METHOD_ATTRIBUTE_STATIC)
383
384 static gboolean
385 mono_method_is_constructor (MonoMethod *method) 
386 {
387         return ((method->flags & CTOR_REQUIRED_FLAGS) == CTOR_REQUIRED_FLAGS &&
388                         !(method->flags & CTOR_INVALID_FLAGS) &&
389                         !strcmp (".ctor", method->name));
390 }
391
392 static gboolean
393 mono_class_has_default_constructor (MonoClass *klass)
394 {
395         MonoMethod *method;
396         int i;
397
398         mono_class_setup_methods (klass);
399
400         for (i = 0; i < klass->method.count; ++i) {
401                 method = klass->methods [i];
402                 if (mono_method_is_constructor (method) &&
403                         mono_method_signature (method)->param_count == 0 &&
404                         (method->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC)
405                         return TRUE;
406         }
407         return FALSE;
408 }
409
410 static gboolean
411 mono_class_interface_implements_interface (MonoClass *candidate, MonoClass *iface)
412 {
413         int i;
414         do {
415                 if (candidate == iface)
416                         return TRUE;
417                 mono_class_setup_interfaces (candidate);
418                 for (i = 0; i < candidate->interface_count; ++i) {
419                         if (candidate->interfaces [i] == iface || mono_class_interface_implements_interface (candidate->interfaces [i], iface))
420                                 return TRUE;
421                 }
422                 candidate = candidate->parent;
423         } while (candidate);
424         return FALSE;
425 }
426
427 /*
428  * Verify if @type is valid for the given @ctx verification context.
429  * this function checks for VAR and MVAR types that are invalid under the current verifier,
430  */
431 static gboolean
432 mono_type_is_valid_type_in_context (MonoType *type, MonoGenericContext *context)
433 {
434         int i;
435         MonoGenericInst *inst;
436
437         switch (type->type) {
438         case MONO_TYPE_VAR:
439         case MONO_TYPE_MVAR:
440                 if (!context)
441                         return FALSE;
442                 inst = type->type == MONO_TYPE_VAR ? context->class_inst : context->method_inst;
443                 if (!inst || mono_type_get_generic_param_num (type) >= inst->type_argc)
444                         return FALSE;
445                 break;
446         case MONO_TYPE_SZARRAY:
447                 return mono_type_is_valid_type_in_context (&type->data.klass->byval_arg, context);
448         case MONO_TYPE_ARRAY:
449                 return mono_type_is_valid_type_in_context (&type->data.array->eklass->byval_arg, context);
450         case MONO_TYPE_PTR:
451                 return mono_type_is_valid_type_in_context (type->data.type, context);
452         case MONO_TYPE_GENERICINST:
453                 inst = type->data.generic_class->context.class_inst;
454                 if (!inst->is_open)
455                         break;
456                 for (i = 0; i < inst->type_argc; ++i)
457                         if (!mono_type_is_valid_type_in_context (inst->type_argv [i], context))
458                                 return FALSE;
459                 break;
460         }
461         return TRUE;
462 }
463
464 /*This function returns NULL if the type is not instantiatable*/
465 static MonoType*
466 verifier_inflate_type (VerifyContext *ctx, MonoType *type, MonoGenericContext *context)
467 {
468         if (!mono_type_is_valid_type_in_context (type, context))
469                 return NULL;
470         return mono_class_inflate_generic_type (type, context);
471 }
472 /*
473  * Test if @candidate is a subtype of @target using the minimal possible information
474  * TODO move the code for non finished TypeBuilders to here.
475  */
476 static gboolean
477 mono_class_is_constraint_compatible (MonoClass *candidate, MonoClass *target)
478 {
479         if (candidate == target)
480                 return TRUE;
481         if (target == mono_defaults.object_class)
482                         return TRUE;
483
484         //setup_supertypes don't mono_class_init anything
485         mono_class_setup_supertypes (candidate);
486         mono_class_setup_supertypes (target);
487
488         if (mono_class_has_parent (candidate, target))
489                 return TRUE;
490
491         //if target is not a supertype it must be an interface
492         if (!MONO_CLASS_IS_INTERFACE (target))
493                         return FALSE;
494
495         if (candidate->image->dynamic && !candidate->wastypebuilder) {
496                 MonoReflectionTypeBuilder *tb = candidate->reflection_info;
497                 int j;
498                 if (tb->interfaces) {
499                         for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
500                                 MonoReflectionType *iface = mono_array_get (tb->interfaces, MonoReflectionType*, j);
501                                 MonoClass *ifaceClass = mono_class_from_mono_type (iface->type);
502                                 if (mono_class_is_constraint_compatible (ifaceClass, target)) {
503                                         return TRUE;
504                                 }
505                         }
506                 }
507                 return FALSE;
508         }
509         return mono_class_interface_implements_interface (candidate, target);
510 }
511
512 static gboolean
513 is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
514 {
515         int i;
516
517         if (ginst->type_argc != gc->type_argc)
518                 return FALSE;
519
520         for (i = 0; i < gc->type_argc; ++i) {
521                 MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
522                 MonoClass *paramClass;
523                 MonoClass **constraints;
524
525                 if (!param_info->constraints && !(param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK))
526                         continue;
527                 if (mono_type_is_generic_argument (ginst->type_argv [i]))
528                         continue; //it's not our job to validate type variables
529
530                 paramClass = mono_class_from_mono_type (ginst->type_argv [i]);
531
532                 if (paramClass->exception_type != MONO_EXCEPTION_NONE)
533                         return FALSE;
534
535                 /*it's not safe to call mono_class_init from here*/
536                 if (paramClass->generic_class && !paramClass->inited) {
537                         if (!mono_class_is_valid_generic_instantiation (NULL, paramClass))
538                                 return FALSE;
539                 }
540
541                 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && (!paramClass->valuetype || mono_class_is_nullable (paramClass)))
542                         return FALSE;
543
544                 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && paramClass->valuetype)
545                         return FALSE;
546
547                 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !paramClass->valuetype && !mono_class_has_default_constructor (paramClass))
548                         return FALSE;
549
550                 if (!param_info->constraints)
551                         continue;
552
553                 for (constraints = param_info->constraints; *constraints; ++constraints) {
554                         MonoClass *ctr = *constraints;
555                         MonoType *inflated;
556
557                         inflated = mono_class_inflate_generic_type (&ctr->byval_arg, context);
558                         ctr = mono_class_from_mono_type (inflated);
559                         mono_metadata_free_type (inflated);
560
561                         if (!mono_class_is_constraint_compatible (paramClass, ctr))
562                                 return FALSE;
563                 }
564         }
565         return TRUE;
566 }
567
568 /*
569  * Return true if @candidate is constraint compatible with @target.
570  * 
571  * This means that @candidate constraints are a super set of @target constaints
572  */
573 static gboolean
574 mono_generic_param_is_constraint_compatible (VerifyContext *ctx, MonoGenericParam *target, MonoGenericParam *candidate, MonoGenericContext *context)
575 {
576         MonoGenericParamInfo *tinfo = mono_generic_param_info (target);
577         MonoGenericParamInfo *cinfo = mono_generic_param_info (candidate);
578
579         int tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
580         int cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
581         if ((tmask & cmask) != tmask)
582                 return FALSE;
583
584         if (tinfo->constraints) {
585                 MonoClass **target_class, **candidate_class;
586                 if (!cinfo->constraints)
587                         return FALSE;
588                 for (target_class = tinfo->constraints; *target_class; ++target_class) {
589                         MonoClass *tc;
590                         MonoType *inflated = verifier_inflate_type (ctx, &(*target_class)->byval_arg, context);
591                         if (!inflated)
592                                 return FALSE;
593                         tc = mono_class_from_mono_type (inflated);
594                         mono_metadata_free_type (inflated);
595
596                         for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
597                                 MonoClass *cc;
598                                 inflated = verifier_inflate_type (ctx, &(*candidate_class)->byval_arg, ctx->generic_context);
599                                 if (!inflated)
600                                         return FALSE;
601                                 cc = mono_class_from_mono_type (inflated);
602                                 mono_metadata_free_type (inflated);
603
604                                 if (mono_class_is_assignable_from (tc, cc))
605                                         break;
606                         }
607                         if (!*candidate_class)
608                                 return FALSE;
609                 }
610         }
611         return TRUE;
612 }
613
614 static MonoGenericParam*
615 verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type)
616 {
617         MonoGenericContainer *gc;
618         MonoMethod *method = ctx->method;
619         int num;
620
621         num = mono_type_get_generic_param_num (type);
622
623         if (type->type == MONO_TYPE_VAR) {
624                 MonoClass *gtd = method->klass;
625                 if (gtd->generic_class)
626                         gtd = gtd->generic_class->container_class;
627                 gc = gtd->generic_container;
628         } else { //MVAR
629                 MonoMethod *gmd = method;
630                 if (method->is_inflated)
631                         gmd = ((MonoMethodInflated*)method)->declaring;
632                 gc = mono_method_get_generic_container (gmd);
633         }
634         if (!gc)
635                 return FALSE;
636         return mono_generic_container_get_param (gc, num);
637 }
638
639
640
641 /*
642  * Verify if @type is valid for the given @ctx verification context.
643  * this function checks for VAR and MVAR types that are invalid under the current verifier,
644  * This means that it either 
645  */
646 static gboolean
647 is_valid_type_in_context (VerifyContext *ctx, MonoType *type)
648 {
649         return mono_type_is_valid_type_in_context (type, ctx->generic_context);
650 }
651
652 static gboolean
653 is_valid_generic_instantiation_in_context (VerifyContext *ctx, MonoGenericInst *ginst)
654 {
655         int i;
656         for (i = 0; i < ginst->type_argc; ++i) {
657                 MonoType *type = ginst->type_argv [i];
658                 if (!is_valid_type_in_context (ctx, type))
659                         return FALSE;
660         }
661         return TRUE;
662 }
663
664 static gboolean
665 generic_arguments_respect_constraints (VerifyContext *ctx, MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
666 {
667         int i;
668         for (i = 0; i < ginst->type_argc; ++i) {
669                 MonoType *type = ginst->type_argv [i];
670                 MonoGenericParam *target = mono_generic_container_get_param (gc, i);
671                 MonoGenericParam *candidate;
672
673                 if (!mono_type_is_generic_argument (type))
674                         continue;
675
676                 if (!is_valid_type_in_context (ctx, type))
677                         return FALSE;
678
679                 candidate = verifier_get_generic_param_from_type (ctx, type);
680
681                 if (!mono_generic_param_is_constraint_compatible (ctx, target, candidate, context))
682                         return FALSE;
683         }
684         return TRUE;
685 }
686
687 static gboolean
688 mono_method_repect_method_constraints (VerifyContext *ctx, MonoMethod *method)
689 {
690         MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
691         MonoGenericInst *ginst = gmethod->context.method_inst;
692         MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
693         return !gc || generic_arguments_respect_constraints (ctx, gc, &gmethod->context, ginst);
694 }
695
696 static gboolean
697 mono_class_repect_method_constraints (VerifyContext *ctx, MonoClass *klass)
698 {
699         MonoGenericClass *gklass = klass->generic_class;
700         MonoGenericInst *ginst = gklass->context.class_inst;
701         MonoGenericContainer *gc = gklass->container_class->generic_container;
702         return !gc || generic_arguments_respect_constraints (ctx, gc, &gklass->context, ginst);
703 }
704
705 static gboolean
706 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method)
707 {
708         MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
709         MonoGenericInst *ginst = gmethod->context.method_inst;
710         MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
711         if (!gc) /*non-generic inflated method - it's part of a generic type  */
712                 return TRUE;
713         if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst))
714                 return FALSE;
715         return is_valid_generic_instantiation (gc, &gmethod->context, ginst);
716
717 }
718
719 static gboolean
720 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass)
721 {
722         MonoGenericClass *gklass = klass->generic_class;
723         MonoGenericInst *ginst = gklass->context.class_inst;
724         MonoGenericContainer *gc = gklass->container_class->generic_container;
725         if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst))
726                 return FALSE;
727         return is_valid_generic_instantiation (gc, &gklass->context, ginst);
728 }
729
730 static gboolean
731 mono_type_is_valid_in_context (VerifyContext *ctx, MonoType *type)
732 {
733         MonoClass *klass;
734
735         if (type == NULL) {
736                 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid null type at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
737                 return FALSE;
738         }
739
740         if (!is_valid_type_in_context (ctx, type)) {
741                 char *str = mono_type_full_name (type);
742                 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type (%s%s) (argument out of range or %s is not generic) at 0x%04x",
743                         type->type == MONO_TYPE_VAR ? "!" : "!!",
744                         str,
745                         type->type == MONO_TYPE_VAR ? "class" : "method",
746                         ctx->ip_offset),
747                         MONO_EXCEPTION_BAD_IMAGE);              
748                 g_free (str);
749                 return FALSE;
750         }
751
752         klass = mono_class_from_mono_type (type);
753         mono_class_init (klass);
754         if (mono_loader_get_last_error () || klass->exception_type != MONO_EXCEPTION_NONE) {
755                 if (klass->generic_class && !mono_class_is_valid_generic_instantiation (NULL, klass))
756                         ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic instantiation of type %s.%s at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
757                 else
758                         ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Could not load type %s.%s at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
759                 return FALSE;
760         }
761
762         if (klass->generic_class && klass->generic_class->container_class->exception_type != MONO_EXCEPTION_NONE) {
763                 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Could not load type %s.%s at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
764                 return FALSE;
765         }
766
767         if (!klass->generic_class)
768                 return TRUE;
769
770         if (!mono_class_is_valid_generic_instantiation (ctx, klass)) {
771                 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type instantiation of type %s.%s at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
772                 return FALSE;
773         }
774
775         if (!mono_class_repect_method_constraints (ctx, klass)) {
776                 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type instantiation of type %s.%s (generic args don't respect target's constraints) at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
777                 return FALSE;
778         }
779
780         return TRUE;
781 }
782
783 static verify_result_t
784 mono_method_is_valid_in_context (VerifyContext *ctx, MonoMethod *method)
785 {
786         if (!mono_type_is_valid_in_context (ctx, &method->klass->byval_arg))
787                 return RESULT_INVALID;
788
789         if (!method->is_inflated)
790                 return RESULT_VALID;
791
792         if (!mono_method_is_valid_generic_instantiation (ctx, method)) {
793                 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic method instantiation of method %s.%s::%s at 0x%04x", method->klass->name_space, method->klass->name, method->name, ctx->ip_offset), MONO_EXCEPTION_UNVERIFIABLE_IL);
794                 return RESULT_INVALID;
795         }
796
797         if (!mono_method_repect_method_constraints (ctx, method)) {
798                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid generic method instantiation of method %s.%s::%s (generic args don't respect target's constraints) at 0x%04x", method->klass->name_space, method->klass->name, method->name, ctx->ip_offset));
799                 return RESULT_UNVERIFIABLE;
800         }
801         return RESULT_VALID;
802 }
803
804         
805 static MonoClassField*
806 verifier_load_field (VerifyContext *ctx, int token, MonoClass **out_klass, const char *opcode) {
807         MonoClassField *field;
808         MonoClass *klass = NULL;
809
810         if (!IS_FIELD_DEF_OR_REF (token) || !token_bounds_check (ctx->image, token)) {
811                 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);
812                 return NULL;
813         }
814
815         field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context);
816         if (!field || !field->parent || !klass) {
817                 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);
818                 return NULL;
819         }
820
821         if (!mono_type_is_valid_in_context (ctx, &klass->byval_arg))
822                 return NULL;
823
824         *out_klass = klass;
825         return field;
826 }
827
828 static MonoMethod*
829 verifier_load_method (VerifyContext *ctx, int token, const char *opcode) {
830         MonoMethod* method;
831         
832         if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
833                 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);
834                 return NULL;
835         }
836
837         method = mono_get_method_full (ctx->image, token, NULL, ctx->generic_context);
838
839         if (!method) {
840                 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);
841                 return NULL;
842         }
843         
844         if (mono_method_is_valid_in_context (ctx, method) == RESULT_INVALID)
845                 return NULL;
846
847         return method;
848 }
849
850 static MonoType*
851 verifier_load_type (VerifyContext *ctx, int token, const char *opcode) {
852         MonoType* type;
853         
854         if (!IS_TYPE_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
855                 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid type token 0x%08x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
856                 return NULL;
857         }
858
859         type = mono_type_get_full (ctx->image, token, ctx->generic_context);
860
861         if (!type) {
862                 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);
863                 return NULL;
864         }
865
866         if (!mono_type_is_valid_in_context (ctx, type))
867                 return NULL;
868
869         return type;
870 }
871
872
873 /* stack_slot_get_type:
874  * 
875  * Returns the stack type of @value. This value includes POINTER_MASK.
876  * 
877  * Use this function to checks that account for a managed pointer.
878  */
879 static gint32
880 stack_slot_get_type (ILStackDesc *value)
881 {
882         return value->stype & RAW_TYPE_MASK;
883 }
884
885 /* stack_slot_get_underlying_type:
886  * 
887  * Returns the stack type of @value. This value does not include POINTER_MASK.
888  * 
889  * Use this function is cases where the fact that the value could be a managed pointer is
890  * irrelevant. For example, field load doesn't care about this fact of type on stack.
891  */
892 static gint32
893 stack_slot_get_underlying_type (ILStackDesc *value)
894 {
895         return value->stype & TYPE_MASK;
896 }
897
898 /* stack_slot_is_managed_pointer:
899  * 
900  * Returns TRUE is @value is a managed pointer.
901  */
902 static gboolean
903 stack_slot_is_managed_pointer (ILStackDesc *value)
904 {
905         return (value->stype & POINTER_MASK) == POINTER_MASK;
906 }
907
908 /* stack_slot_is_managed_mutability_pointer:
909  * 
910  * Returns TRUE is @value is a managed mutability pointer.
911  */
912 static G_GNUC_UNUSED gboolean
913 stack_slot_is_managed_mutability_pointer (ILStackDesc *value)
914 {
915         return (value->stype & CMMP_MASK) == CMMP_MASK;
916 }
917
918 /* stack_slot_is_null_literal:
919  * 
920  * Returns TRUE is @value is the null literal.
921  */
922 static gboolean
923 stack_slot_is_null_literal (ILStackDesc *value)
924 {
925         return (value->stype & NULL_LITERAL_MASK) == NULL_LITERAL_MASK;
926 }
927
928
929 /* stack_slot_is_this_pointer:
930  * 
931  * Returns TRUE is @value is the this literal
932  */
933 static gboolean
934 stack_slot_is_this_pointer (ILStackDesc *value)
935 {
936         return (value->stype & THIS_POINTER_MASK) == THIS_POINTER_MASK;
937 }
938
939 /* stack_slot_is_boxed_value:
940  * 
941  * Returns TRUE is @value is a boxed value
942  */
943 static gboolean
944 stack_slot_is_boxed_value (ILStackDesc *value)
945 {
946         return (value->stype & BOXED_MASK) == BOXED_MASK;
947 }
948
949 static const char *
950 stack_slot_get_name (ILStackDesc *value)
951 {
952         return type_names [value->stype & TYPE_MASK];
953 }
954
955 #define APPEND_WITH_PREDICATE(PRED,NAME) do {\
956         if (PRED (value)) { \
957                 if (!first) \
958                         g_string_append (str, ", "); \
959                 g_string_append (str, NAME); \
960                 first = FALSE; \
961         } } while (0)
962
963 static char*
964 stack_slot_stack_type_full_name (ILStackDesc *value)
965 {
966         GString *str = g_string_new ("");
967         char *result;
968
969         if ((value->stype & TYPE_MASK) != value->stype) {
970                 gboolean first = TRUE;
971                 g_string_append(str, "[");
972                 APPEND_WITH_PREDICATE (stack_slot_is_this_pointer, "this");
973                 APPEND_WITH_PREDICATE (stack_slot_is_boxed_value, "boxed");
974                 APPEND_WITH_PREDICATE (stack_slot_is_null_literal, "null");
975                 APPEND_WITH_PREDICATE (stack_slot_is_managed_mutability_pointer, "cmmp");
976                 APPEND_WITH_PREDICATE (stack_slot_is_managed_pointer, "mp");
977                 g_string_append(str, "] ");
978         }
979
980         g_string_append (str, stack_slot_get_name (value));
981         result = str->str;
982         g_string_free (str, FALSE);
983         return result;
984 }
985
986 static char*
987 stack_slot_full_name (ILStackDesc *value)
988 {
989         char *type_name = mono_type_full_name (value->type);
990         char *stack_name = stack_slot_stack_type_full_name (value);
991         char *res = g_strdup_printf ("%s (%s)", type_name, stack_name);
992         g_free (type_name);
993         g_free (stack_name);
994         return res;
995 }
996
997 //////////////////////////////////////////////////////////////////
998 void
999 mono_free_verify_list (GSList *list)
1000 {
1001         MonoVerifyInfoExtended *info;
1002         GSList *tmp;
1003
1004         for (tmp = list; tmp; tmp = tmp->next) {
1005                 info = tmp->data;
1006                 g_free (info->info.message);
1007                 g_free (info);
1008         }
1009         g_slist_free (list);
1010 }
1011
1012 #define ADD_ERROR(list,msg)     \
1013         do {    \
1014                 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1);      \
1015                 vinfo->info.status = MONO_VERIFY_ERROR; \
1016                 vinfo->info.message = (msg);    \
1017                 (list) = g_slist_prepend ((list), vinfo);       \
1018         } while (0)
1019
1020 #define ADD_WARN(list,code,msg) \
1021         do {    \
1022                 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1);      \
1023                 vinfo->info.status = (code);    \
1024                 vinfo->info.message = (msg);    \
1025                 (list) = g_slist_prepend ((list), vinfo);       \
1026         } while (0)
1027
1028 static const char
1029 valid_cultures[][9] = {
1030         "ar-SA", "ar-IQ", "ar-EG", "ar-LY",
1031         "ar-DZ", "ar-MA", "ar-TN", "ar-OM",
1032         "ar-YE", "ar-SY", "ar-JO", "ar-LB",
1033         "ar-KW", "ar-AE", "ar-BH", "ar-QA",
1034         "bg-BG", "ca-ES", "zh-TW", "zh-CN",
1035         "zh-HK", "zh-SG", "zh-MO", "cs-CZ",
1036         "da-DK", "de-DE", "de-CH", "de-AT",
1037         "de-LU", "de-LI", "el-GR", "en-US",
1038         "en-GB", "en-AU", "en-CA", "en-NZ",
1039         "en-IE", "en-ZA", "en-JM", "en-CB",
1040         "en-BZ", "en-TT", "en-ZW", "en-PH",
1041         "es-ES-Ts", "es-MX", "es-ES-Is", "es-GT",
1042         "es-CR", "es-PA", "es-DO", "es-VE",
1043         "es-CO", "es-PE", "es-AR", "es-EC",
1044         "es-CL", "es-UY", "es-PY", "es-BO",
1045         "es-SV", "es-HN", "es-NI", "es-PR",
1046         "Fi-FI", "fr-FR", "fr-BE", "fr-CA",
1047         "Fr-CH", "fr-LU", "fr-MC", "he-IL",
1048         "hu-HU", "is-IS", "it-IT", "it-CH",
1049         "Ja-JP", "ko-KR", "nl-NL", "nl-BE",
1050         "nb-NO", "nn-NO", "pl-PL", "pt-BR",
1051         "pt-PT", "ro-RO", "ru-RU", "hr-HR",
1052         "Lt-sr-SP", "Cy-sr-SP", "sk-SK", "sq-AL",
1053         "sv-SE", "sv-FI", "th-TH", "tr-TR",
1054         "ur-PK", "id-ID", "uk-UA", "be-BY",
1055         "sl-SI", "et-EE", "lv-LV", "lt-LT",
1056         "fa-IR", "vi-VN", "hy-AM", "Lt-az-AZ",
1057         "Cy-az-AZ",
1058         "eu-ES", "mk-MK", "af-ZA",
1059         "ka-GE", "fo-FO", "hi-IN", "ms-MY",
1060         "ms-BN", "kk-KZ", "ky-KZ", "sw-KE",
1061         "Lt-uz-UZ", "Cy-uz-UZ", "tt-TA", "pa-IN",
1062         "gu-IN", "ta-IN", "te-IN", "kn-IN",
1063         "mr-IN", "sa-IN", "mn-MN", "gl-ES",
1064         "kok-IN", "syr-SY", "div-MV"
1065 };
1066
1067 static int
1068 is_valid_culture (const char *cname)
1069 {
1070         int i;
1071         int found;
1072
1073         found = *cname == 0;
1074         for (i = 0; i < G_N_ELEMENTS (valid_cultures); ++i) {
1075                 if (g_strcasecmp (valid_cultures [i], cname)) {
1076                         found = 1;
1077                         break;
1078                 }
1079         }
1080         return found;
1081 }
1082
1083 static int
1084 is_valid_assembly_flags (guint32 flags) {
1085         /* Metadata: 22.1.2 */
1086         flags &= ~(0x8000 | 0x4000); /* ignore reserved bits 0x0030? */
1087         return ((flags == 1) || (flags == 0));
1088 }
1089
1090 static int
1091 is_valid_blob (MonoImage *image, guint32 blob_index, int notnull)
1092 {
1093         guint32 size;
1094         const char *p, *blob_end;
1095
1096         if (blob_index >= image->heap_blob.size)
1097                 return 0;
1098         p = mono_metadata_blob_heap (image, blob_index);
1099         size = mono_metadata_decode_blob_size (p, &blob_end);
1100         if (blob_index + size + (blob_end-p) > image->heap_blob.size)
1101                 return 0;
1102         if (notnull && !size)
1103                 return 0;
1104         return 1;
1105 }
1106
1107 static const char*
1108 is_valid_string (MonoImage *image, guint32 str_index, int notnull)
1109 {
1110         const char *p, *blob_end, *res;
1111
1112         if (str_index >= image->heap_strings.size)
1113                 return NULL;
1114         res = p = mono_metadata_string_heap (image, str_index);
1115         blob_end = mono_metadata_string_heap (image, image->heap_strings.size - 1);
1116         if (notnull && !*p)
1117                 return 0;
1118         /* 
1119          * FIXME: should check it's a valid utf8 string, too.
1120          */
1121         while (p <= blob_end) {
1122                 if (!*p)
1123                         return res;
1124                 ++p;
1125         }
1126         return *p? NULL: res;
1127 }
1128
1129 static int
1130 is_valid_cls_ident (const char *p)
1131 {
1132         /*
1133          * FIXME: we need the full unicode glib support for this.
1134          * Check: http://www.unicode.org/unicode/reports/tr15/Identifier.java
1135          * We do the lame thing for now.
1136          */
1137         if (!isalpha (*p))
1138                 return 0;
1139         ++p;
1140         while (*p) {
1141                 if (!isalnum (*p) && *p != '_')
1142                         return 0;
1143                 ++p;
1144         }
1145         return 1;
1146 }
1147
1148 static int
1149 is_valid_filename (const char *p)
1150 {
1151         if (!*p)
1152                 return 0;
1153         return strpbrk (p, "\\//:")? 0: 1;
1154 }
1155
1156 static GSList*
1157 verify_assembly_table (MonoImage *image, GSList *list, int level)
1158 {
1159         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
1160         guint32 cols [MONO_ASSEMBLY_SIZE];
1161         const char *p;
1162
1163         if (level & MONO_VERIFY_ERROR) {
1164                 if (t->rows > 1)
1165                         ADD_ERROR (list, g_strdup ("Assembly table may only have 0 or 1 rows"));
1166                 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
1167
1168                 switch (cols [MONO_ASSEMBLY_HASH_ALG]) {
1169                 case ASSEMBLY_HASH_NONE:
1170                 case ASSEMBLY_HASH_MD5:
1171                 case ASSEMBLY_HASH_SHA1:
1172                         break;
1173                 default:
1174                         ADD_ERROR (list, g_strdup_printf ("Hash algorithm 0x%x unknown", cols [MONO_ASSEMBLY_HASH_ALG]));
1175                 }
1176
1177                 if (!is_valid_assembly_flags (cols [MONO_ASSEMBLY_FLAGS]))
1178                         ADD_ERROR (list, g_strdup_printf ("Invalid flags in assembly: 0x%x", cols [MONO_ASSEMBLY_FLAGS]));
1179
1180                 if (!is_valid_blob (image, cols [MONO_ASSEMBLY_PUBLIC_KEY], FALSE))
1181                         ADD_ERROR (list, g_strdup ("Assembly public key is an invalid index"));
1182
1183                 if (!(p = is_valid_string (image, cols [MONO_ASSEMBLY_NAME], TRUE))) {
1184                         ADD_ERROR (list, g_strdup ("Assembly name is invalid"));
1185                 } else {
1186                         if (strpbrk (p, ":\\/."))
1187                                 ADD_ERROR (list, g_strdup_printf ("Assembly name `%s' contains invalid chars", p));
1188                 }
1189
1190                 if (!(p = is_valid_string (image, cols [MONO_ASSEMBLY_CULTURE], FALSE))) {
1191                         ADD_ERROR (list, g_strdup ("Assembly culture is an invalid index"));
1192                 } else {
1193                         if (!is_valid_culture (p))
1194                                 ADD_ERROR (list, g_strdup_printf ("Assembly culture `%s' is invalid", p));
1195                 }
1196         }
1197         return list;
1198 }
1199
1200 static GSList*
1201 verify_assemblyref_table (MonoImage *image, GSList *list, int level)
1202 {
1203         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1204         guint32 cols [MONO_ASSEMBLYREF_SIZE];
1205         const char *p;
1206         int i;
1207
1208         if (level & MONO_VERIFY_ERROR) {
1209                 for (i = 0; i < t->rows; ++i) {
1210                         mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
1211                         if (!is_valid_assembly_flags (cols [MONO_ASSEMBLYREF_FLAGS]))
1212                                 ADD_ERROR (list, g_strdup_printf ("Invalid flags in assemblyref row %d: 0x%x", i + 1, cols [MONO_ASSEMBLY_FLAGS]));
1213
1214                         if (!is_valid_blob (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], FALSE))
1215                                 ADD_ERROR (list, g_strdup_printf ("AssemblyRef public key in row %d is an invalid index", i + 1));
1216
1217                         if (!(p = is_valid_string (image, cols [MONO_ASSEMBLYREF_CULTURE], FALSE))) {
1218                                 ADD_ERROR (list, g_strdup_printf ("AssemblyRef culture in row %d is invalid", i + 1));
1219                         } else {
1220                                 if (!is_valid_culture (p))
1221                                         ADD_ERROR (list, g_strdup_printf ("AssemblyRef culture `%s' in row %d is invalid", p, i + 1));
1222                         }
1223
1224                         if (cols [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob (image, cols [MONO_ASSEMBLYREF_HASH_VALUE], TRUE))
1225                                 ADD_ERROR (list, g_strdup_printf ("AssemblyRef hash value in row %d is invalid or not null and empty", i + 1));
1226                 }
1227         }
1228         if (level & MONO_VERIFY_WARNING) {
1229                 /* check for duplicated rows */
1230                 for (i = 0; i < t->rows; ++i) {
1231                 }
1232         }
1233         return list;
1234 }
1235
1236 static GSList*
1237 verify_class_layout_table (MonoImage *image, GSList *list, int level)
1238 {
1239         MonoTableInfo *t = &image->tables [MONO_TABLE_CLASSLAYOUT];
1240         MonoTableInfo *tdef = &image->tables [MONO_TABLE_TYPEDEF];
1241         guint32 cols [MONO_CLASS_LAYOUT_SIZE];
1242         guint32 value, i;
1243
1244         if (level & MONO_VERIFY_ERROR) {
1245                 for (i = 0; i < t->rows; ++i) {
1246                         mono_metadata_decode_row (t, i, cols, MONO_CLASS_LAYOUT_SIZE);
1247
1248                         if (cols [MONO_CLASS_LAYOUT_PARENT] > tdef->rows || !cols [MONO_CLASS_LAYOUT_PARENT]) {
1249                                 ADD_ERROR (list, g_strdup_printf ("Parent in class layout is invalid in row %d", i + 1));
1250                         } else {
1251                                 value = mono_metadata_decode_row_col (tdef, cols [MONO_CLASS_LAYOUT_PARENT] - 1, MONO_TYPEDEF_FLAGS);
1252                                 if (value & TYPE_ATTRIBUTE_INTERFACE)
1253                                         ADD_ERROR (list, g_strdup_printf ("Parent in class layout row %d is an interface", i + 1));
1254                                 if (value & TYPE_ATTRIBUTE_AUTO_LAYOUT)
1255                                         ADD_ERROR (list, g_strdup_printf ("Parent in class layout row %d is AutoLayout", i + 1));
1256                                 if (value & TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT) {
1257                                         switch (cols [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
1258                                         case 0: case 1: case 2: case 4: case 8: case 16:
1259                                         case 32: case 64: case 128: break;
1260                                         default:
1261                                                 ADD_ERROR (list, g_strdup_printf ("Packing size %d in class layout row %d is invalid", cols [MONO_CLASS_LAYOUT_PACKING_SIZE], i + 1));
1262                                         }
1263                                 } else if (value & TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
1264                                         /*
1265                                          * FIXME: LAMESPEC: it claims it must be 0 (it's 1, instead).
1266                                         if (cols [MONO_CLASS_LAYOUT_PACKING_SIZE])
1267                                                 ADD_ERROR (list, g_strdup_printf ("Packing size %d in class layout row %d is invalid with explicit layout", cols [MONO_CLASS_LAYOUT_PACKING_SIZE], i + 1));
1268                                         */
1269                                 }
1270                                 /*
1271                                  * FIXME: we need to check that if class size != 0, 
1272                                  * it needs to be greater than the class calculated size.
1273                                  * If parent is a valuetype it also needs to be smaller than
1274                                  * 1 MByte (0x100000 bytes).
1275                                  * To do both these checks we need to load the referenced 
1276                                  * assemblies, though (the spec claims we didn't have to, bah).
1277                                  */
1278                                 /* 
1279                                  * We need to check that the parent types have the same layout 
1280                                  * type as well.
1281                                  */
1282                         }
1283                 }
1284         }
1285
1286         return list;
1287 }
1288
1289 static GSList*
1290 verify_constant_table (MonoImage *image, GSList *list, int level)
1291 {
1292         MonoTableInfo *t = &image->tables [MONO_TABLE_CONSTANT];
1293         guint32 cols [MONO_CONSTANT_SIZE];
1294         guint32 value, i;
1295         GHashTable *dups = g_hash_table_new (NULL, NULL);
1296
1297         for (i = 0; i < t->rows; ++i) {
1298                 mono_metadata_decode_row (t, i, cols, MONO_CONSTANT_SIZE);
1299
1300                 if (level & MONO_VERIFY_ERROR)
1301                         if (g_hash_table_lookup (dups, GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT])))
1302                                 ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is duplicated in Constant row %d", cols [MONO_CONSTANT_PARENT], i + 1));
1303                 g_hash_table_insert (dups, GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT]),
1304                                 GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT]));
1305
1306                 switch (cols [MONO_CONSTANT_TYPE]) {
1307                 case MONO_TYPE_U1: /* LAMESPEC: it says I1...*/
1308                 case MONO_TYPE_U2:
1309                 case MONO_TYPE_U4:
1310                 case MONO_TYPE_U8:
1311                         if (level & MONO_VERIFY_CLS)
1312                                 ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Type 0x%x not CLS compliant in Constant row %d", cols [MONO_CONSTANT_TYPE], i + 1));
1313                 case MONO_TYPE_BOOLEAN:
1314                 case MONO_TYPE_CHAR:
1315                 case MONO_TYPE_I1:
1316                 case MONO_TYPE_I2:
1317                 case MONO_TYPE_I4:
1318                 case MONO_TYPE_I8:
1319                 case MONO_TYPE_R4:
1320                 case MONO_TYPE_R8:
1321                 case MONO_TYPE_STRING:
1322                 case MONO_TYPE_CLASS:
1323                         break;
1324                 default:
1325                         if (level & MONO_VERIFY_ERROR)
1326                                 ADD_ERROR (list, g_strdup_printf ("Type 0x%x is invalid in Constant row %d", cols [MONO_CONSTANT_TYPE], i + 1));
1327                 }
1328                 if (level & MONO_VERIFY_ERROR) {
1329                         value = cols [MONO_CONSTANT_PARENT] >> MONO_HASCONSTANT_BITS;
1330                         switch (cols [MONO_CONSTANT_PARENT] & MONO_HASCONSTANT_MASK) {
1331                         case MONO_HASCONSTANT_FIEDDEF:
1332                                 if (value > image->tables [MONO_TABLE_FIELD].rows)
1333                                         ADD_ERROR (list, g_strdup_printf ("Parent (field) is invalid in Constant row %d", i + 1));
1334                                 break;
1335                         case MONO_HASCONSTANT_PARAM:
1336                                 if (value > image->tables [MONO_TABLE_PARAM].rows)
1337                                         ADD_ERROR (list, g_strdup_printf ("Parent (param) is invalid in Constant row %d", i + 1));
1338                                 break;
1339                         case MONO_HASCONSTANT_PROPERTY:
1340                                 if (value > image->tables [MONO_TABLE_PROPERTY].rows)
1341                                         ADD_ERROR (list, g_strdup_printf ("Parent (property) is invalid in Constant row %d", i + 1));
1342                                 break;
1343                         default:
1344                                 ADD_ERROR (list, g_strdup_printf ("Parent is invalid in Constant row %d", i + 1));
1345                                 break;
1346                         }
1347                 }
1348                 if (level & MONO_VERIFY_CLS) {
1349                         /* 
1350                          * FIXME: verify types is consistent with the enum type
1351                          * is parent is an enum.
1352                          */
1353                 }
1354         }
1355         g_hash_table_destroy (dups);
1356         return list;
1357 }
1358
1359 static GSList*
1360 verify_event_map_table (MonoImage *image, GSList *list, int level)
1361 {
1362         MonoTableInfo *t = &image->tables [MONO_TABLE_EVENTMAP];
1363         guint32 cols [MONO_EVENT_MAP_SIZE];
1364         guint32 i, last_event;
1365         GHashTable *dups = g_hash_table_new (NULL, NULL);
1366
1367         last_event = 0;
1368
1369         for (i = 0; i < t->rows; ++i) {
1370                 mono_metadata_decode_row (t, i, cols, MONO_EVENT_MAP_SIZE);
1371                 if (level & MONO_VERIFY_ERROR)
1372                         if (g_hash_table_lookup (dups, GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT])))
1373                                 ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is duplicated in Event Map row %d", cols [MONO_EVENT_MAP_PARENT], i + 1));
1374                 g_hash_table_insert (dups, GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT]),
1375                                 GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT]));
1376                 if (level & MONO_VERIFY_ERROR) {
1377                         if (cols [MONO_EVENT_MAP_PARENT] > image->tables [MONO_TABLE_TYPEDEF].rows)
1378                                 ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is invalid in Event Map row %d", cols [MONO_EVENT_MAP_PARENT], i + 1));
1379                         if (cols [MONO_EVENT_MAP_EVENTLIST] > image->tables [MONO_TABLE_EVENT].rows)
1380                                 ADD_ERROR (list, g_strdup_printf ("EventList 0x%08x is invalid in Event Map row %d", cols [MONO_EVENT_MAP_EVENTLIST], i + 1));
1381
1382                         if (cols [MONO_EVENT_MAP_EVENTLIST] <= last_event)
1383                                 ADD_ERROR (list, g_strdup_printf ("EventList overlap in Event Map row %d", i + 1));
1384                         last_event = cols [MONO_EVENT_MAP_EVENTLIST];
1385                 }
1386         }
1387
1388         g_hash_table_destroy (dups);
1389         return list;
1390 }
1391
1392 static GSList*
1393 verify_event_table (MonoImage *image, GSList *list, int level)
1394 {
1395         MonoTableInfo *t = &image->tables [MONO_TABLE_EVENT];
1396         guint32 cols [MONO_EVENT_SIZE];
1397         const char *p;
1398         guint32 value, i;
1399
1400         for (i = 0; i < t->rows; ++i) {
1401                 mono_metadata_decode_row (t, i, cols, MONO_EVENT_SIZE);
1402
1403                 if (cols [MONO_EVENT_FLAGS] & ~(EVENT_SPECIALNAME|EVENT_RTSPECIALNAME)) {
1404                         if (level & MONO_VERIFY_ERROR)
1405                                 ADD_ERROR (list, g_strdup_printf ("Flags 0x%04x invalid in Event row %d", cols [MONO_EVENT_FLAGS], i + 1));
1406                 }
1407                 if (!(p = is_valid_string (image, cols [MONO_EVENT_NAME], TRUE))) {
1408                         if (level & MONO_VERIFY_ERROR)
1409                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in Event row %d", i + 1));
1410                 } else {
1411                         if (level & MONO_VERIFY_CLS) {
1412                                 if (!is_valid_cls_ident (p))
1413                                         ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Invalid CLS name '%s` in Event row %d", p, i + 1));
1414                         }
1415                 }
1416
1417                 if (level & MONO_VERIFY_ERROR && cols [MONO_EVENT_TYPE]) {
1418                         value = cols [MONO_EVENT_TYPE] >> MONO_TYPEDEFORREF_BITS;
1419                         switch (cols [MONO_EVENT_TYPE] & MONO_TYPEDEFORREF_MASK) {
1420                         case MONO_TYPEDEFORREF_TYPEDEF:
1421                                 if (!value || value > image->tables [MONO_TABLE_TYPEDEF].rows)
1422                                         ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
1423                                 break;
1424                         case MONO_TYPEDEFORREF_TYPEREF:
1425                                 if (!value || value > image->tables [MONO_TABLE_TYPEREF].rows)
1426                                         ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
1427                                 break;
1428                         case MONO_TYPEDEFORREF_TYPESPEC:
1429                                 if (!value || value > image->tables [MONO_TABLE_TYPESPEC].rows)
1430                                         ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
1431                                 break;
1432                         default:
1433                                 ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
1434                         }
1435                 }
1436                 /*
1437                  * FIXME: check that there is 1 add and remove row in methodsemantics
1438                  * and 0 or 1 raise and 0 or more other (maybe it's better to check for 
1439                  * these while checking methodsemantics).
1440                  * check for duplicated names for the same type [ERROR]
1441                  * check for CLS duplicate names for the same type [CLS]
1442                  */
1443         }
1444         return list;
1445 }
1446
1447 static GSList*
1448 verify_field_table (MonoImage *image, GSList *list, int level)
1449 {
1450         MonoTableInfo *t = &image->tables [MONO_TABLE_FIELD];
1451         guint32 cols [MONO_FIELD_SIZE];
1452         const char *p;
1453         guint32 i, flags;
1454
1455         for (i = 0; i < t->rows; ++i) {
1456                 mono_metadata_decode_row (t, i, cols, MONO_FIELD_SIZE);
1457                 /*
1458                  * Check this field has only one owner and that the owner is not 
1459                  * an interface (done in verify_typedef_table() )
1460                  */
1461                 flags = cols [MONO_FIELD_FLAGS];
1462                 switch (flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) {
1463                 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
1464                 case FIELD_ATTRIBUTE_PRIVATE:
1465                 case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
1466                 case FIELD_ATTRIBUTE_ASSEMBLY:
1467                 case FIELD_ATTRIBUTE_FAMILY:
1468                 case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
1469                 case FIELD_ATTRIBUTE_PUBLIC:
1470                         break;
1471                 default:
1472                         if (level & MONO_VERIFY_ERROR)
1473                                 ADD_ERROR (list, g_strdup_printf ("Invalid access mask in Field row %d", i + 1));
1474                         break;
1475                 }
1476                 if (level & MONO_VERIFY_ERROR) {
1477                         if ((flags & FIELD_ATTRIBUTE_LITERAL) && (flags & FIELD_ATTRIBUTE_INIT_ONLY))
1478                                 ADD_ERROR (list, g_strdup_printf ("Literal and InitOnly cannot be both set in Field row %d", i + 1));
1479                         if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
1480                                 ADD_ERROR (list, g_strdup_printf ("Literal needs also Static set in Field row %d", i + 1));
1481                         if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
1482                                 ADD_ERROR (list, g_strdup_printf ("RTSpecialName needs also SpecialName set in Field row %d", i + 1));
1483                         /*
1484                          * FIXME: check there is only one owner in the respective table.
1485                          * if (flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
1486                          * if (flags & FIELD_ATTRIBUTE_HAS_DEFAULT)
1487                          * if (flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA)
1488                          */
1489                 }
1490                 if (!(p = is_valid_string (image, cols [MONO_FIELD_NAME], TRUE))) {
1491                         if (level & MONO_VERIFY_ERROR)
1492                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in Field row %d", i + 1));
1493                 } else {
1494                         if (level & MONO_VERIFY_CLS) {
1495                                 if (!is_valid_cls_ident (p))
1496                                         ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Invalid CLS name '%s` in Field row %d", p, i + 1));
1497                         }
1498                 }
1499                 /*
1500                  * check signature.
1501                  * if owner is module needs to be static, access mask needs to be compilercontrolled,
1502                  * public or private (not allowed in cls mode).
1503                  * if owner is an enum ...
1504                  */
1505
1506
1507         }
1508         return list;
1509 }
1510
1511 static GSList*
1512 verify_file_table (MonoImage *image, GSList *list, int level)
1513 {
1514         MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
1515         guint32 cols [MONO_FILE_SIZE];
1516         const char *p;
1517         guint32 i;
1518         GHashTable *dups = g_hash_table_new (g_str_hash, g_str_equal);
1519
1520         for (i = 0; i < t->rows; ++i) {
1521                 mono_metadata_decode_row (t, i, cols, MONO_FILE_SIZE);
1522                 if (level & MONO_VERIFY_ERROR) {
1523                         if (cols [MONO_FILE_FLAGS] != FILE_CONTAINS_METADATA && cols [MONO_FILE_FLAGS] != FILE_CONTAINS_NO_METADATA)
1524                                 ADD_ERROR (list, g_strdup_printf ("Invalid flags in File row %d", i + 1));
1525                         if (!is_valid_blob (image, cols [MONO_FILE_HASH_VALUE], TRUE))
1526                                 ADD_ERROR (list, g_strdup_printf ("File hash value in row %d is invalid or not null and empty", i + 1));
1527                 }
1528                 if (!(p = is_valid_string (image, cols [MONO_FILE_NAME], TRUE))) {
1529                         if (level & MONO_VERIFY_ERROR)
1530                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in File row %d", i + 1));
1531                 } else {
1532                         if (level & MONO_VERIFY_ERROR) {
1533                                 if (!is_valid_filename (p))
1534                                         ADD_ERROR (list, g_strdup_printf ("Invalid name '%s` in File row %d", p, i + 1));
1535                                 else if (g_hash_table_lookup (dups, p)) {
1536                                         ADD_ERROR (list, g_strdup_printf ("Duplicate name '%s` in File row %d", p, i + 1));
1537                                 }
1538                                 g_hash_table_insert (dups, (gpointer)p, (gpointer)p);
1539                         }
1540                 }
1541                 /*
1542                  * FIXME: I don't understand what this means:
1543                  * If this module contains a row in the Assembly table (that is, if this module "holds the manifest") 
1544                  * then there shall not be any row in the File table for this module - i.e., no self-reference  [ERROR]
1545                  */
1546
1547         }
1548         if (level & MONO_VERIFY_WARNING) {
1549                 if (!t->rows && image->tables [MONO_TABLE_EXPORTEDTYPE].rows)
1550                         ADD_WARN (list, MONO_VERIFY_WARNING, g_strdup ("ExportedType table should be empty if File table is empty"));
1551         }
1552         g_hash_table_destroy (dups);
1553         return list;
1554 }
1555
1556 static GSList*
1557 verify_moduleref_table (MonoImage *image, GSList *list, int level)
1558 {
1559         MonoTableInfo *t = &image->tables [MONO_TABLE_MODULEREF];
1560         MonoTableInfo *tfile = &image->tables [MONO_TABLE_FILE];
1561         guint32 cols [MONO_MODULEREF_SIZE];
1562         const char *p, *pf;
1563         guint32 found, i, j, value;
1564         GHashTable *dups = g_hash_table_new (g_str_hash, g_str_equal);
1565
1566         for (i = 0; i < t->rows; ++i) {
1567                 mono_metadata_decode_row (t, i, cols, MONO_MODULEREF_SIZE);
1568                 if (!(p = is_valid_string (image, cols [MONO_MODULEREF_NAME], TRUE))) {
1569                         if (level & MONO_VERIFY_ERROR)
1570                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in ModuleRef row %d", i + 1));
1571                 } else {
1572                         if (level & MONO_VERIFY_ERROR) {
1573                                 if (!is_valid_filename (p))
1574                                         ADD_ERROR (list, g_strdup_printf ("Invalid name '%s` in ModuleRef row %d", p, i + 1));
1575                                 else if (g_hash_table_lookup (dups, p)) {
1576                                         ADD_WARN (list, MONO_VERIFY_WARNING, g_strdup_printf ("Duplicate name '%s` in ModuleRef row %d", p, i + 1));
1577                                         g_hash_table_insert (dups, (gpointer)p, (gpointer)p);
1578                                         found = 0;
1579                                         for (j = 0; j < tfile->rows; ++j) {
1580                                                 value = mono_metadata_decode_row_col (tfile, j, MONO_FILE_NAME);
1581                                                 if ((pf = is_valid_string (image, value, TRUE)))
1582                                                         if (strcmp (p, pf) == 0) {
1583                                                                 found = 1;
1584                                                                 break;
1585                                                         }
1586                                         }
1587                                         if (!found)
1588                                                 ADD_ERROR (list, g_strdup_printf ("Name '%s` in ModuleRef row %d doesn't have a match in File table", p, i + 1));
1589                                 }
1590                         }
1591                 }
1592         }
1593         g_hash_table_destroy (dups);
1594         return list;
1595 }
1596
1597 static GSList*
1598 verify_standalonesig_table (MonoImage *image, GSList *list, int level)
1599 {
1600         MonoTableInfo *t = &image->tables [MONO_TABLE_STANDALONESIG];
1601         guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE];
1602         const char *p;
1603         guint32 i;
1604
1605         for (i = 0; i < t->rows; ++i) {
1606                 mono_metadata_decode_row (t, i, cols, MONO_STAND_ALONE_SIGNATURE_SIZE);
1607                 if (level & MONO_VERIFY_ERROR) {
1608                         if (!is_valid_blob (image, cols [MONO_STAND_ALONE_SIGNATURE], TRUE)) {
1609                                 ADD_ERROR (list, g_strdup_printf ("Signature is invalid in StandAloneSig row %d", i + 1));
1610                         } else {
1611                                 p = mono_metadata_blob_heap (image, cols [MONO_STAND_ALONE_SIGNATURE]);
1612                                 /* FIXME: check it's a valid locals or method sig.*/
1613                         }
1614                 }
1615         }
1616         return list;
1617 }
1618
1619 GSList*
1620 mono_image_verify_tables (MonoImage *image, int level)
1621 {
1622         GSList *error_list = NULL;
1623
1624         error_list = verify_assembly_table (image, error_list, level);
1625         /* 
1626          * AssemblyOS, AssemblyProcessor, AssemblyRefOs and
1627          * AssemblyRefProcessor should be ignored, 
1628          * though we may want to emit a warning, since it should not 
1629          * be present in a PE file.
1630          */
1631         error_list = verify_assemblyref_table (image, error_list, level);
1632         error_list = verify_class_layout_table (image, error_list, level);
1633         error_list = verify_constant_table (image, error_list, level);
1634         /*
1635          * cutom attribute, declsecurity 
1636          */
1637         error_list = verify_event_map_table (image, error_list, level);
1638         error_list = verify_event_table (image, error_list, level);
1639         error_list = verify_field_table (image, error_list, level);
1640         error_list = verify_file_table (image, error_list, level);
1641         error_list = verify_moduleref_table (image, error_list, level);
1642         error_list = verify_standalonesig_table (image, error_list, level);
1643
1644         return g_slist_reverse (error_list);
1645 }
1646
1647 #define ADD_INVALID(list,msg)   \
1648         do {    \
1649                 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1);      \
1650                 vinfo->status = MONO_VERIFY_ERROR;      \
1651                 vinfo->message = (msg); \
1652                 (list) = g_slist_prepend ((list), vinfo);       \
1653                 /*G_BREAKPOINT ();*/    \
1654                 goto invalid_cil;       \
1655         } while (0)
1656
1657 #define CHECK_STACK_UNDERFLOW(num)      \
1658         do {    \
1659                 if (cur_stack < (num))  \
1660                         ADD_INVALID (list, g_strdup_printf ("Stack underflow at 0x%04x (%d items instead of %d)", ip_offset, cur_stack, (num)));        \
1661         } while (0)
1662
1663 #define CHECK_STACK_OVERFLOW()  \
1664         do {    \
1665                 if (cur_stack >= max_stack)     \
1666                         ADD_INVALID (list, g_strdup_printf ("Maxstack exceeded at 0x%04x", ip_offset)); \
1667         } while (0)
1668
1669
1670 static int
1671 in_any_block (MonoMethodHeader *header, guint offset)
1672 {
1673         int i;
1674         MonoExceptionClause *clause;
1675
1676         for (i = 0; i < header->num_clauses; ++i) {
1677                 clause = &header->clauses [i];
1678                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1679                         return 1;
1680                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1681                         return 1;
1682                 if (MONO_OFFSET_IN_FILTER (clause, offset))
1683                         return 1;
1684         }
1685         return 0;
1686 }
1687
1688 /*
1689  * in_any_exception_block:
1690  * 
1691  * Returns TRUE is @offset is part of any exception clause (filter, handler, catch, finally or fault).
1692  */
1693 static gboolean
1694 in_any_exception_block (MonoMethodHeader *header, guint offset)
1695 {
1696         int i;
1697         MonoExceptionClause *clause;
1698
1699         for (i = 0; i < header->num_clauses; ++i) {
1700                 clause = &header->clauses [i];
1701                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1702                         return TRUE;
1703                 if (MONO_OFFSET_IN_FILTER (clause, offset))
1704                         return TRUE;
1705         }
1706         return FALSE;
1707 }
1708
1709 /*
1710  * is_valid_branch_instruction:
1711  *
1712  * Verify if it's valid to perform a branch from @offset to @target.
1713  * This should be used with br and brtrue/false.
1714  * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1715  * The major diferent from other similiar functions is that branching into a
1716  * finally/fault block is invalid instead of just unverifiable.  
1717  */
1718 static int
1719 is_valid_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1720 {
1721         int i;
1722         MonoExceptionClause *clause;
1723
1724         for (i = 0; i < header->num_clauses; ++i) {
1725                 clause = &header->clauses [i];
1726                 /*branching into a finally block is invalid*/
1727                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) &&
1728                         !MONO_OFFSET_IN_HANDLER (clause, offset) &&
1729                         MONO_OFFSET_IN_HANDLER (clause, target))
1730                         return 2;
1731
1732                 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1733                         return 1;
1734                 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1735                         return 1;
1736                 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1737                         return 1;
1738         }
1739         return 0;
1740 }
1741
1742 /*
1743  * is_valid_cmp_branch_instruction:
1744  * 
1745  * Verify if it's valid to perform a branch from @offset to @target.
1746  * This should be used with binary comparison branching instruction, like beq, bge and similars.
1747  * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1748  * 
1749  * The major diferences from other similar functions are that most errors lead to invalid
1750  * code and only branching out of finally, filter or fault clauses is unverifiable. 
1751  */
1752 static int
1753 is_valid_cmp_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1754 {
1755         int i;
1756         MonoExceptionClause *clause;
1757
1758         for (i = 0; i < header->num_clauses; ++i) {
1759                 clause = &header->clauses [i];
1760                 /*branching out of a handler or finally*/
1761                 if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE &&
1762                         MONO_OFFSET_IN_HANDLER (clause, offset) &&
1763                         !MONO_OFFSET_IN_HANDLER (clause, target))
1764                         return 1;
1765
1766                 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1767                         return 2;
1768                 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1769                         return 2;
1770                 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1771                         return 2;
1772         }
1773         return 0;
1774 }
1775
1776 /*
1777  * A leave can't escape a finally block 
1778  */
1779 static int
1780 is_correct_leave (MonoMethodHeader *header, guint offset, guint target)
1781 {
1782         int i;
1783         MonoExceptionClause *clause;
1784
1785         for (i = 0; i < header->num_clauses; ++i) {
1786                 clause = &header->clauses [i];
1787                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY && MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
1788                         return 0;
1789                 if (MONO_OFFSET_IN_FILTER (clause, offset))
1790                         return 0;
1791         }
1792         return 1;
1793 }
1794
1795 /*
1796  * A rethrow can't happen outside of a catch handler.
1797  */
1798 static int
1799 is_correct_rethrow (MonoMethodHeader *header, guint offset)
1800 {
1801         int i;
1802         MonoExceptionClause *clause;
1803
1804         for (i = 0; i < header->num_clauses; ++i) {
1805                 clause = &header->clauses [i];
1806                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1807                         return 1;
1808                 if (MONO_OFFSET_IN_FILTER (clause, offset))
1809                         return 1;
1810         }
1811         return 0;
1812 }
1813
1814 /*
1815  * An endfinally can't happen outside of a finally/fault handler.
1816  */
1817 static int
1818 is_correct_endfinally (MonoMethodHeader *header, guint offset)
1819 {
1820         int i;
1821         MonoExceptionClause *clause;
1822
1823         for (i = 0; i < header->num_clauses; ++i) {
1824                 clause = &header->clauses [i];
1825                 if (MONO_OFFSET_IN_HANDLER (clause, offset) && (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY))
1826                         return 1;
1827         }
1828         return 0;
1829 }
1830
1831
1832 /*
1833  * An endfilter can only happens inside a filter clause.
1834  * In non-strict mode filter is allowed inside the handler clause too
1835  */
1836 static MonoExceptionClause *
1837 is_correct_endfilter (VerifyContext *ctx, guint offset)
1838 {
1839         int i;
1840         MonoExceptionClause *clause;
1841
1842         for (i = 0; i < ctx->header->num_clauses; ++i) {
1843                 clause = &ctx->header->clauses [i];
1844                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER)
1845                         continue;
1846                 if (MONO_OFFSET_IN_FILTER (clause, offset))
1847                         return clause;
1848                 if (!IS_STRICT_MODE (ctx) && MONO_OFFSET_IN_HANDLER (clause, offset))
1849                         return clause;
1850         }
1851         return NULL;
1852 }
1853
1854
1855 /*
1856  * Non-strict endfilter can happens inside a try block or any handler block
1857  */
1858 static int
1859 is_unverifiable_endfilter (VerifyContext *ctx, guint offset)
1860 {
1861         int i;
1862         MonoExceptionClause *clause;
1863
1864         for (i = 0; i < ctx->header->num_clauses; ++i) {
1865                 clause = &ctx->header->clauses [i];
1866                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1867                         return 1;
1868         }
1869         return 0;
1870 }
1871
1872 static gboolean
1873 is_valid_bool_arg (ILStackDesc *arg)
1874 {
1875         if (stack_slot_is_managed_pointer (arg) || stack_slot_is_boxed_value (arg) || stack_slot_is_null_literal (arg))
1876                 return TRUE;
1877
1878
1879         switch (stack_slot_get_underlying_type (arg)) {
1880         case TYPE_I4:
1881         case TYPE_I8:
1882         case TYPE_NATIVE_INT:
1883         case TYPE_PTR:
1884                 return TRUE;
1885         case TYPE_COMPLEX:
1886                 g_assert (arg->type);
1887                 switch (arg->type->type) {
1888                 case MONO_TYPE_CLASS:
1889                 case MONO_TYPE_STRING:
1890                 case MONO_TYPE_OBJECT:
1891                 case MONO_TYPE_SZARRAY:
1892                 case MONO_TYPE_ARRAY:
1893                 case MONO_TYPE_FNPTR:
1894                 case MONO_TYPE_PTR:
1895                         return TRUE;
1896                 case MONO_TYPE_GENERICINST:
1897                         /*We need to check if the container class
1898                          * of the generic type is a valuetype, iow:
1899                          * is it a "class Foo<T>" or a "struct Foo<T>"?
1900                          */
1901                         return !arg->type->data.generic_class->container_class->valuetype;
1902                 }
1903         default:
1904                 return FALSE;
1905         }
1906 }
1907
1908
1909 /*Type manipulation helper*/
1910
1911 /*Returns the byref version of the supplied MonoType*/
1912 static MonoType*
1913 mono_type_get_type_byref (MonoType *type)
1914 {
1915         if (type->byref)
1916                 return type;
1917         return &mono_class_from_mono_type (type)->this_arg;
1918 }
1919
1920
1921 /*Returns the byval version of the supplied MonoType*/
1922 static MonoType*
1923 mono_type_get_type_byval (MonoType *type)
1924 {
1925         if (!type->byref)
1926                 return type;
1927         return &mono_class_from_mono_type (type)->byval_arg;
1928 }
1929
1930 static MonoType*
1931 mono_type_from_stack_slot (ILStackDesc *slot)
1932 {
1933         if (stack_slot_is_managed_pointer (slot))
1934                 return mono_type_get_type_byref (slot->type);
1935         return slot->type;
1936 }
1937
1938 /*Stack manipulation code*/
1939
1940 static void
1941 stack_init (VerifyContext *ctx, ILCodeDesc *state) 
1942 {
1943         if (state->flags & IL_CODE_FLAG_STACK_INITED)
1944                 return;
1945         state->size = 0;
1946         state->flags |= IL_CODE_FLAG_STACK_INITED;
1947         if (!state->stack)
1948                 state->stack = g_new0 (ILStackDesc, ctx->max_stack);
1949 }
1950
1951 static void
1952 stack_copy (ILCodeDesc *to, ILCodeDesc *from)
1953 {
1954         to->size = from->size;
1955         memcpy (to->stack, from->stack, sizeof (ILStackDesc) * from->size);
1956 }
1957
1958 static void
1959 copy_stack_value (ILStackDesc *to, ILStackDesc *from)
1960 {
1961         to->stype = from->stype;
1962         to->type = from->type;
1963         to->method = from->method;
1964 }
1965
1966 static int
1967 check_underflow (VerifyContext *ctx, int size)
1968 {
1969         if (ctx->eval.size < size) {
1970                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack underflow, required %d, but have %d at 0x%04x", size, ctx->eval.size, ctx->ip_offset));
1971                 return 0;
1972         }
1973         return 1;
1974 }
1975
1976 static int
1977 check_overflow (VerifyContext *ctx)
1978 {
1979         if (ctx->eval.size >= ctx->max_stack) {
1980                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have stack-depth %d at 0x%04x", ctx->eval.size + 1, ctx->ip_offset));
1981                 return 0;
1982         }
1983         return 1;
1984 }
1985
1986 /*This reject out PTR, FNPTR and TYPEDBYREF*/
1987 static gboolean
1988 check_unmanaged_pointer (VerifyContext *ctx, ILStackDesc *value)
1989 {
1990         if (stack_slot_get_type (value) == TYPE_PTR) {
1991                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1992                 return 0;
1993         }
1994         return 1;
1995 }
1996
1997 /*TODO verify if MONO_TYPE_TYPEDBYREF is not allowed here as well.*/
1998 static gboolean
1999 check_unverifiable_type (VerifyContext *ctx, MonoType *type)
2000 {
2001         if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
2002                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
2003                 return 0;
2004         }
2005         return 1;
2006 }
2007
2008
2009 static ILStackDesc *
2010 stack_push (VerifyContext *ctx)
2011 {
2012         return & ctx->eval.stack [ctx->eval.size++];
2013 }
2014
2015 static ILStackDesc *
2016 stack_push_val (VerifyContext *ctx, int stype, MonoType *type)
2017 {
2018         ILStackDesc *top = stack_push (ctx);
2019         top->stype = stype;
2020         top->type = type;
2021         return top;
2022 }
2023
2024 static ILStackDesc *
2025 stack_pop (VerifyContext *ctx)
2026 {
2027         ILStackDesc *ret = ctx->eval.stack + --ctx->eval.size;
2028         if ((ret->stype & UNINIT_THIS_MASK) == UNINIT_THIS_MASK)
2029                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Found use of uninitialized 'this ptr' ref at 0x%04x", ctx->ip_offset));
2030         return ret;
2031 }
2032
2033 /* This function allows to safely pop an unititialized this ptr from
2034  * the eval stack without marking the method as unverifiable. 
2035  */
2036 static ILStackDesc *
2037 stack_pop_safe (VerifyContext *ctx)
2038 {
2039         return ctx->eval.stack + --ctx->eval.size;
2040 }
2041
2042 static ILStackDesc *
2043 stack_push_stack_val (VerifyContext *ctx, ILStackDesc *value)
2044 {
2045         ILStackDesc *top = stack_push (ctx);
2046         copy_stack_value (top, value);
2047         return top;
2048 }
2049
2050 /* Returns the MonoType associated with the token, or NULL if it is invalid.
2051  * 
2052  * A boxable type can be either a reference or value type, but cannot be a byref type or an unmanaged pointer   
2053  * */
2054 static MonoType*
2055 get_boxable_mono_type (VerifyContext* ctx, int token, const char *opcode)
2056 {
2057         MonoType *type;
2058         MonoClass *class;
2059
2060         if (!(type = verifier_load_type (ctx, token, opcode)))
2061                 return NULL;
2062
2063         if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
2064                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type for %s at 0x%04x", opcode, ctx->ip_offset));
2065                 return NULL;
2066         }
2067
2068         if (type->type == MONO_TYPE_VOID) {
2069                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type for %s at 0x%04x", opcode, ctx->ip_offset));
2070                 return NULL;
2071         }
2072
2073         if (type->type == MONO_TYPE_TYPEDBYREF)
2074                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid use of typedbyref for %s at 0x%04x", opcode, ctx->ip_offset));
2075
2076         if (!(class = mono_class_from_mono_type (type)))
2077                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not retrieve type token for %s at 0x%04x", opcode, ctx->ip_offset));
2078
2079         if (class->generic_container && type->type != MONO_TYPE_GENERICINST)
2080                 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));      
2081
2082         check_unverifiable_type (ctx, type);
2083         return type;
2084 }
2085
2086
2087 /*operation result tables */
2088
2089 static const unsigned char bin_op_table [TYPE_MAX][TYPE_MAX] = {
2090         {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
2091         {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2092         {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
2093         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
2094         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2095         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2096 };
2097
2098 static const unsigned char add_table [TYPE_MAX][TYPE_MAX] = {
2099         {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
2100         {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2101         {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
2102         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
2103         {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
2104         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2105 };
2106
2107 static const unsigned char sub_table [TYPE_MAX][TYPE_MAX] = {
2108         {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
2109         {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2110         {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
2111         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
2112         {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
2113         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2114 };
2115
2116 static const unsigned char int_bin_op_table [TYPE_MAX][TYPE_MAX] = {
2117         {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
2118         {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2119         {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
2120         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2121         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2122         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2123 };
2124
2125 static const unsigned char shift_op_table [TYPE_MAX][TYPE_MAX] = {
2126         {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
2127         {TYPE_I8, TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV},
2128         {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
2129         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2130         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2131         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2132 };
2133
2134 static const unsigned char cmp_br_op [TYPE_MAX][TYPE_MAX] = {
2135         {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
2136         {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2137         {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
2138         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
2139         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV},
2140         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2141 };
2142
2143 static const unsigned char cmp_br_eq_op [TYPE_MAX][TYPE_MAX] = {
2144         {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
2145         {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2146         {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV},
2147         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
2148         {TYPE_INV, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_I4, TYPE_INV},
2149         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4},
2150 };
2151
2152 static const unsigned char add_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
2153         {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
2154         {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2155         {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
2156         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2157         {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
2158         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2159 };
2160
2161 static const unsigned char sub_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
2162         {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
2163         {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2164         {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
2165         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2166         {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
2167         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2168 };
2169
2170 static const unsigned char bin_ovf_table [TYPE_MAX][TYPE_MAX] = {
2171         {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
2172         {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2173         {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
2174         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2175         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2176         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
2177 };
2178
2179 #ifdef MONO_VERIFIER_DEBUG
2180
2181 /*debug helpers */
2182 static void
2183 dump_stack_value (ILStackDesc *value)
2184 {
2185         printf ("[(%x)(%x)", value->type->type, value->stype);
2186
2187         if (stack_slot_is_this_pointer (value))
2188                 printf ("[this] ");
2189
2190         if (stack_slot_is_boxed_value (value))
2191                 printf ("[boxed] ");
2192
2193         if (stack_slot_is_null_literal (value))
2194                 printf ("[null] ");
2195
2196         if (stack_slot_is_managed_mutability_pointer (value))
2197                 printf ("Controled Mutability MP: ");
2198
2199         if (stack_slot_is_managed_pointer (value))
2200                 printf ("Managed Pointer to: ");
2201
2202         switch (stack_slot_get_underlying_type (value)) {
2203                 case TYPE_INV:
2204                         printf ("invalid type]"); 
2205                         return;
2206                 case TYPE_I4:
2207                         printf ("int32]"); 
2208                         return;
2209                 case TYPE_I8:
2210                         printf ("int64]"); 
2211                         return;
2212                 case TYPE_NATIVE_INT:
2213                         printf ("native int]"); 
2214                         return;
2215                 case TYPE_R8:
2216                         printf ("float64]"); 
2217                         return;
2218                 case TYPE_PTR:
2219                         printf ("unmanaged pointer]"); 
2220                         return;
2221                 case TYPE_COMPLEX:
2222                         switch (value->type->type) {
2223                         case MONO_TYPE_CLASS:
2224                         case MONO_TYPE_VALUETYPE:
2225                                 printf ("complex] (%s)", value->type->data.klass->name);
2226                                 return;
2227                         case MONO_TYPE_STRING:
2228                                 printf ("complex] (string)");
2229                                 return;
2230                         case MONO_TYPE_OBJECT:
2231                                 printf ("complex] (object)");
2232                                 return;
2233                         case MONO_TYPE_SZARRAY:
2234                                 printf ("complex] (%s [])", value->type->data.klass->name);
2235                                 return;
2236                         case MONO_TYPE_ARRAY:
2237                                 printf ("complex] (%s [%d %d %d])",
2238                                         value->type->data.array->eklass->name,
2239                                         value->type->data.array->rank,
2240                                         value->type->data.array->numsizes,
2241                                         value->type->data.array->numlobounds);
2242                                 return;
2243                         case MONO_TYPE_GENERICINST:
2244                                 printf ("complex] (inst of %s )", value->type->data.generic_class->container_class->name);
2245                                 return;
2246                         case MONO_TYPE_VAR:
2247                                 printf ("complex] (type generic param !%d - %s) ", value->type->data.generic_param->num, mono_generic_param_info (value->type->data.generic_param)->name);
2248                                 return;
2249                         case MONO_TYPE_MVAR:
2250                                 printf ("complex] (method generic param !!%d - %s) ", value->type->data.generic_param->num, mono_generic_param_info (value->type->data.generic_param)->name);
2251                                 return;
2252                         default: {
2253                                 //should be a boxed value 
2254                                 char * name = mono_type_full_name (value->type);
2255                                 printf ("complex] %s", name);
2256                                 g_free (name);
2257                                 return;
2258                                 }
2259                         }
2260                 default:
2261                         printf ("unknown stack %x type]\n", value->stype);
2262                         g_assert_not_reached ();
2263         }
2264 }
2265
2266 static void
2267 dump_stack_state (ILCodeDesc *state) 
2268 {
2269         int i;
2270
2271         printf ("(%d) ", state->size);
2272         for (i = 0; i < state->size; ++i)
2273                 dump_stack_value (state->stack + i);
2274         printf ("\n");
2275 }
2276 #endif
2277
2278 /*Returns TRUE if candidate array type can be assigned to target.
2279  *Both parameters MUST be of type MONO_TYPE_ARRAY (target->type == MONO_TYPE_ARRAY)
2280  */
2281 static gboolean
2282 is_array_type_compatible (MonoType *target, MonoType *candidate)
2283 {
2284         MonoArrayType *left = target->data.array;
2285         MonoArrayType *right = candidate->data.array;
2286
2287         g_assert (target->type == MONO_TYPE_ARRAY);
2288         g_assert (candidate->type == MONO_TYPE_ARRAY);
2289
2290         if (left->rank != right->rank)
2291                 return FALSE;
2292
2293         return mono_class_is_assignable_from (left->eklass, right->eklass);
2294 }
2295
2296 static int
2297 get_stack_type (MonoType *type)
2298 {
2299         int mask = 0;
2300         int type_kind = type->type;
2301         if (type->byref)
2302                 mask = POINTER_MASK;
2303         /*TODO handle CMMP_MASK */
2304
2305 handle_enum:
2306         switch (type_kind) {
2307         case MONO_TYPE_I1:
2308         case MONO_TYPE_U1:
2309         case MONO_TYPE_BOOLEAN:
2310         case MONO_TYPE_I2:
2311         case MONO_TYPE_U2:
2312         case MONO_TYPE_CHAR:
2313         case MONO_TYPE_I4:
2314         case MONO_TYPE_U4:
2315                 return TYPE_I4 | mask;
2316
2317         case MONO_TYPE_I:
2318         case MONO_TYPE_U:
2319                 return TYPE_NATIVE_INT | mask;
2320
2321         /* FIXME: the spec says that you cannot have a pointer to method pointer, do we need to check this here? */ 
2322         case MONO_TYPE_FNPTR:
2323         case MONO_TYPE_PTR:
2324         case MONO_TYPE_TYPEDBYREF:
2325                 return TYPE_PTR | mask;
2326
2327         case MONO_TYPE_VAR:
2328         case MONO_TYPE_MVAR:
2329
2330         case MONO_TYPE_CLASS:
2331         case MONO_TYPE_STRING:
2332         case MONO_TYPE_OBJECT:
2333         case MONO_TYPE_SZARRAY:
2334         case MONO_TYPE_ARRAY:
2335                 return TYPE_COMPLEX | mask;
2336
2337         case MONO_TYPE_GENERICINST:
2338                 if (mono_type_is_enum_type (type)) {
2339                         type = mono_type_get_underlying_type_any (type);
2340                         type_kind = type->type;
2341                         goto handle_enum;
2342                 } else {
2343                         return TYPE_COMPLEX | mask;
2344                 }
2345
2346         case MONO_TYPE_I8:
2347         case MONO_TYPE_U8:
2348                 return TYPE_I8 | mask;
2349
2350         case MONO_TYPE_R4:
2351         case MONO_TYPE_R8:
2352                 return TYPE_R8 | mask;
2353
2354         case MONO_TYPE_VALUETYPE:
2355                 if (mono_type_is_enum_type (type)) {
2356                         type = mono_type_get_underlying_type_any (type);
2357                         type_kind = type->type;
2358                         goto handle_enum;
2359                 } else {
2360                         return TYPE_COMPLEX | mask;
2361                 }
2362
2363         default:
2364                 VERIFIER_DEBUG ( printf ("unknown type %02x in eval stack type\n", type->type); );
2365                 g_assert_not_reached ();
2366                 return 0;
2367         }
2368 }
2369
2370 /* convert MonoType to ILStackDesc format (stype) */
2371 static gboolean
2372 set_stack_value (VerifyContext *ctx, ILStackDesc *stack, MonoType *type, int take_addr)
2373 {
2374         int mask = 0;
2375         int type_kind = type->type;
2376
2377         if (type->byref || take_addr)
2378                 mask = POINTER_MASK;
2379         /* TODO handle CMMP_MASK */
2380
2381 handle_enum:
2382         stack->type = type;
2383
2384         switch (type_kind) {
2385         case MONO_TYPE_I1:
2386         case MONO_TYPE_U1:
2387         case MONO_TYPE_BOOLEAN:
2388         case MONO_TYPE_I2:
2389         case MONO_TYPE_U2:
2390         case MONO_TYPE_CHAR:
2391         case MONO_TYPE_I4:
2392         case MONO_TYPE_U4:
2393                 stack->stype = TYPE_I4 | mask;
2394                 break;
2395         case MONO_TYPE_I:
2396         case MONO_TYPE_U:
2397                 stack->stype = TYPE_NATIVE_INT | mask;
2398                 break;
2399
2400         /*FIXME: Do we need to check if it's a pointer to the method pointer? The spec says it' illegal to have that.*/
2401         case MONO_TYPE_FNPTR:
2402         case MONO_TYPE_PTR:
2403         case MONO_TYPE_TYPEDBYREF:
2404                 stack->stype = TYPE_PTR | mask;
2405                 break;
2406
2407         case MONO_TYPE_CLASS:
2408         case MONO_TYPE_STRING:
2409         case MONO_TYPE_OBJECT:
2410         case MONO_TYPE_SZARRAY:
2411         case MONO_TYPE_ARRAY:
2412
2413         case MONO_TYPE_VAR:
2414         case MONO_TYPE_MVAR: 
2415                 stack->stype = TYPE_COMPLEX | mask;
2416                 break;
2417                 
2418         case MONO_TYPE_GENERICINST:
2419                 if (mono_type_is_enum_type (type)) {
2420                         type = mono_type_get_underlying_type_any (type);
2421                         type_kind = type->type;
2422                         goto handle_enum;
2423                 } else {
2424                         stack->stype = TYPE_COMPLEX | mask;
2425                         break;
2426                 }
2427
2428         case MONO_TYPE_I8:
2429         case MONO_TYPE_U8:
2430                 stack->stype = TYPE_I8 | mask;
2431                 break;
2432         case MONO_TYPE_R4:
2433         case MONO_TYPE_R8:
2434                 stack->stype = TYPE_R8 | mask;
2435                 break;
2436         case MONO_TYPE_VALUETYPE:
2437                 if (mono_type_is_enum_type (type)) {
2438                         type = mono_type_get_underlying_type_any (type);
2439                         type_kind = type->type;
2440                         goto handle_enum;
2441                 } else {
2442                         stack->stype = TYPE_COMPLEX | mask;
2443                         break;
2444                 }
2445         default:
2446                 VERIFIER_DEBUG ( printf ("unknown type 0x%02x in eval stack type\n", type->type); );
2447                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Illegal value set on stack 0x%02x at %d", type->type, ctx->ip_offset));
2448                 return FALSE;
2449         }
2450         return TRUE;
2451 }
2452
2453 /* 
2454  * init_stack_with_value_at_exception_boundary:
2455  * 
2456  * Initialize the stack and push a given type.
2457  * The instruction is marked as been on the exception boundary.
2458  */
2459 static void
2460 init_stack_with_value_at_exception_boundary (VerifyContext *ctx, ILCodeDesc *code, MonoClass *klass)
2461 {
2462         MonoType *type = mono_class_inflate_generic_type (&klass->byval_arg, ctx->generic_context);
2463         stack_init (ctx, code);
2464         set_stack_value (ctx, code->stack, type, FALSE);
2465         ctx->exception_types = g_slist_prepend (ctx->exception_types, type);
2466         code->size = 1;
2467         code->flags |= IL_CODE_FLAG_WAS_TARGET;
2468         if (mono_type_is_generic_argument (type))
2469                 code->stack->stype |= BOXED_MASK;
2470 }
2471
2472 /*Verify if type 'candidate' can be stored in type 'target'.
2473  * 
2474  * If strict, check for the underlying type and not the verification stack types
2475  */
2476 static gboolean
2477 verify_type_compatibility_full (VerifyContext *ctx, MonoType *target, MonoType *candidate, gboolean strict)
2478 {
2479 #define IS_ONE_OF3(T, A, B, C) (T == A || T == B || T == C)
2480 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
2481
2482         MonoType *original_candidate = candidate;
2483         VERIFIER_DEBUG ( printf ("checking type compatibility %s x %s strict %d\n", mono_type_full_name (target), mono_type_full_name (candidate), strict); );
2484
2485         /*only one is byref */
2486         if (candidate->byref ^ target->byref) {
2487                 /* converting from native int to byref*/
2488                 if (get_stack_type (candidate) == TYPE_NATIVE_INT && target->byref) {
2489                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("using byref native int at 0x%04x", ctx->ip_offset));
2490                         return TRUE;
2491                 }
2492                 return FALSE;
2493         }
2494         strict |= target->byref;
2495         /*From now on we don't care about byref anymore, so it's ok to discard it here*/
2496         candidate = mono_type_get_underlying_type_any (candidate);
2497
2498 handle_enum:
2499         switch (target->type) {
2500         case MONO_TYPE_VOID:
2501                 return candidate->type == MONO_TYPE_VOID;
2502         case MONO_TYPE_I1:
2503         case MONO_TYPE_U1:
2504         case MONO_TYPE_BOOLEAN:
2505                 if (strict)
2506                         return IS_ONE_OF3 (candidate->type, MONO_TYPE_I1, MONO_TYPE_U1, MONO_TYPE_BOOLEAN);
2507         case MONO_TYPE_I2:
2508         case MONO_TYPE_U2:
2509         case MONO_TYPE_CHAR:
2510                 if (strict)
2511                         return IS_ONE_OF3 (candidate->type, MONO_TYPE_I2, MONO_TYPE_U2, MONO_TYPE_CHAR);
2512         case MONO_TYPE_I4:
2513         case MONO_TYPE_U4: {
2514                 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2515                 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2516                 if (strict)
2517                         return is_native_int || is_int4;
2518                 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2519         }
2520
2521         case MONO_TYPE_I8:
2522         case MONO_TYPE_U8:
2523                 return IS_ONE_OF2 (candidate->type, MONO_TYPE_I8, MONO_TYPE_U8);
2524
2525         case MONO_TYPE_R4:
2526         case MONO_TYPE_R8:
2527                 if (strict)
2528                         return candidate->type == target->type;
2529                 return IS_ONE_OF2 (candidate->type, MONO_TYPE_R4, MONO_TYPE_R8);
2530
2531         case MONO_TYPE_I:
2532         case MONO_TYPE_U: {
2533                 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2534                 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2535                 if (strict)
2536                         return is_native_int || is_int4;
2537                 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2538         }
2539
2540         case MONO_TYPE_PTR:
2541                 if (candidate->type != MONO_TYPE_PTR)
2542                         return FALSE;
2543                 /* check the underlying type */
2544                 return verify_type_compatibility_full (ctx, target->data.type, candidate->data.type, TRUE);
2545
2546         case MONO_TYPE_FNPTR: {
2547                 MonoMethodSignature *left, *right;
2548                 if (candidate->type != MONO_TYPE_FNPTR)
2549                         return FALSE;
2550
2551                 left = mono_type_get_signature (target);
2552                 right = mono_type_get_signature (candidate);
2553                 return mono_metadata_signature_equal (left, right) && left->call_convention == right->call_convention;
2554         }
2555
2556         case MONO_TYPE_GENERICINST: {
2557                 MonoClass *target_klass;
2558                 MonoClass *candidate_klass;
2559                 if (mono_type_is_enum_type (target)) {
2560                         target = mono_type_get_underlying_type_any (target);
2561                         goto handle_enum;
2562                 }
2563                 target_klass = mono_class_from_mono_type (target);
2564                 candidate_klass = mono_class_from_mono_type (candidate);
2565                 if (mono_class_is_nullable (target_klass)) {
2566                         if (!mono_class_is_nullable (candidate_klass))
2567                                 return FALSE;
2568                         return target_klass == candidate_klass;
2569                 }
2570                 
2571                 return mono_class_is_assignable_from (target_klass, candidate_klass);
2572         }
2573
2574         case MONO_TYPE_STRING:
2575                 return candidate->type == MONO_TYPE_STRING;
2576
2577         case MONO_TYPE_CLASS:
2578                 /*
2579                  * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
2580                  * to take boxing status into account.
2581                  */
2582                 if (mono_type_is_generic_argument (original_candidate))
2583                         return FALSE;
2584                 /* If candidate is an enum it should return true for System.Enum and supertypes.
2585                  * That's why here we use the original type and not the underlying type.
2586                  */ 
2587                 return mono_class_is_assignable_from (target->data.klass, mono_class_from_mono_type (original_candidate));
2588
2589         case MONO_TYPE_OBJECT:
2590                 return MONO_TYPE_IS_REFERENCE (candidate);
2591
2592         case MONO_TYPE_SZARRAY: {
2593                 MonoClass *left;
2594                 MonoClass *right;
2595                 if (candidate->type != MONO_TYPE_SZARRAY)
2596                         return FALSE;
2597
2598                 left = mono_class_from_mono_type (target)->element_class;
2599                 right = mono_class_from_mono_type (candidate)->element_class;
2600                 return mono_class_is_assignable_from (left, right);
2601         }
2602
2603         case MONO_TYPE_ARRAY:
2604                 if (candidate->type != MONO_TYPE_ARRAY)
2605                         return FALSE;
2606                 return is_array_type_compatible (target, candidate);
2607
2608         case MONO_TYPE_TYPEDBYREF:
2609                 return candidate->type == MONO_TYPE_TYPEDBYREF;
2610
2611         case MONO_TYPE_VALUETYPE: {
2612                 MonoClass *target_klass  = mono_class_from_mono_type (target);
2613                 MonoClass *candidate_klass = mono_class_from_mono_type (candidate);
2614
2615                 if (target_klass == candidate_klass)
2616                         return TRUE;
2617                 if (mono_type_is_enum_type (target)) {
2618                         target = mono_type_get_underlying_type_any (target);
2619                         goto handle_enum;
2620                 }
2621                 return FALSE;
2622         }
2623
2624         case MONO_TYPE_VAR:
2625                 if (candidate->type != MONO_TYPE_VAR)
2626                         return FALSE;
2627                 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2628
2629         case MONO_TYPE_MVAR:
2630                 if (candidate->type != MONO_TYPE_MVAR)
2631                         return FALSE;
2632                 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2633
2634         default:
2635                 VERIFIER_DEBUG ( printf ("unknown store type %d\n", target->type); );
2636                 g_assert_not_reached ();
2637                 return FALSE;
2638         }
2639         return 1;
2640 #undef IS_ONE_OF3
2641 #undef IS_ONE_OF2
2642 }
2643
2644 static gboolean
2645 verify_type_compatibility (VerifyContext *ctx, MonoType *target, MonoType *candidate)
2646 {
2647         return verify_type_compatibility_full (ctx, target, candidate, FALSE);
2648 }
2649
2650 /*
2651  * Returns the generic param bound to the context been verified.
2652  * 
2653  */
2654 static MonoGenericParam*
2655 get_generic_param (VerifyContext *ctx, MonoType *param) 
2656 {
2657         guint16 param_num = mono_type_get_generic_param_num (param);
2658         if (param->type == MONO_TYPE_VAR) {
2659                 if (!ctx->generic_context->class_inst || ctx->generic_context->class_inst->type_argc <= param_num) {
2660                         ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic type argument %d", param_num));
2661                         return NULL;
2662                 }
2663                 return ctx->generic_context->class_inst->type_argv [param_num]->data.generic_param;
2664         }
2665         
2666         /*param must be a MVAR */
2667         if (!ctx->generic_context->method_inst || ctx->generic_context->method_inst->type_argc <= param_num) {
2668                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic method argument %d", param_num));
2669                 return NULL;
2670         }
2671         return ctx->generic_context->method_inst->type_argv [param_num]->data.generic_param;
2672         
2673 }
2674 /*
2675  * is_compatible_boxed_valuetype:
2676  * 
2677  * Returns TRUE if @candidate / @stack is a valid boxed valuetype. 
2678  * 
2679  * @type The source type. It it tested to be of the proper type.    
2680  * @candidate type of the boxed valuetype.
2681  * @stack stack slot of the boxed valuetype, separate from @candidade since one could be changed before calling this function
2682  * @strict if TRUE candidate must be boxed compatible to the target type
2683  * 
2684  */
2685 static gboolean
2686 is_compatible_boxed_valuetype (VerifyContext *ctx, MonoType *type, MonoType *candidate, ILStackDesc *stack, gboolean strict)
2687 {
2688         if (!stack_slot_is_boxed_value (stack))
2689                 return FALSE;
2690         if (type->byref || candidate->byref)
2691                 return FALSE;
2692
2693         if (mono_type_is_generic_argument (candidate)) {
2694                 MonoGenericParam *param = get_generic_param (ctx, candidate);
2695                 MonoClass **class;
2696                 for (class = mono_generic_param_info (param)->constraints; class && *class; ++class) {
2697                         if (verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (& (*class)->byval_arg), FALSE))
2698                                 return TRUE;
2699                 }
2700         }
2701
2702         if (mono_type_is_generic_argument (type))
2703                 return FALSE;
2704
2705         if (!strict)
2706                 return TRUE;
2707
2708         return MONO_TYPE_IS_REFERENCE (type) && mono_class_is_assignable_from (mono_class_from_mono_type (type), mono_class_from_mono_type (candidate));
2709 }
2710
2711 static int
2712 verify_stack_type_compatibility_full (VerifyContext *ctx, MonoType *type, ILStackDesc *stack, gboolean drop_byref, gboolean valuetype_must_be_boxed)
2713 {
2714         MonoType *candidate = mono_type_from_stack_slot (stack);
2715         if (MONO_TYPE_IS_REFERENCE (type) && !type->byref && stack_slot_is_null_literal (stack))
2716                 return TRUE;
2717
2718         if (is_compatible_boxed_valuetype (ctx, type, candidate, stack, TRUE))
2719                 return TRUE;
2720
2721         if (valuetype_must_be_boxed && !stack_slot_is_boxed_value (stack) && !MONO_TYPE_IS_REFERENCE (candidate))
2722                 return FALSE;
2723
2724         if (!valuetype_must_be_boxed && stack_slot_is_boxed_value (stack))
2725                 return FALSE;
2726
2727         if (drop_byref)
2728                 return verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (candidate), FALSE);
2729
2730         return verify_type_compatibility_full (ctx, type, candidate, FALSE);
2731 }
2732
2733 static int
2734 verify_stack_type_compatibility (VerifyContext *ctx, MonoType *type, ILStackDesc *stack)
2735 {
2736         return verify_stack_type_compatibility_full (ctx, type, stack, FALSE, FALSE);
2737 }
2738
2739 static gboolean
2740 mono_delegate_type_equal (MonoType *target, MonoType *candidate)
2741 {
2742         if (candidate->byref ^ target->byref)
2743                 return FALSE;
2744
2745         switch (target->type) {
2746         case MONO_TYPE_VOID:
2747         case MONO_TYPE_I1:
2748         case MONO_TYPE_U1:
2749         case MONO_TYPE_BOOLEAN:
2750         case MONO_TYPE_I2:
2751         case MONO_TYPE_U2:
2752         case MONO_TYPE_CHAR:
2753         case MONO_TYPE_I4:
2754         case MONO_TYPE_U4:
2755         case MONO_TYPE_I8:
2756         case MONO_TYPE_U8:
2757         case MONO_TYPE_R4:
2758         case MONO_TYPE_R8:
2759         case MONO_TYPE_I:
2760         case MONO_TYPE_U:
2761         case MONO_TYPE_STRING:
2762         case MONO_TYPE_TYPEDBYREF:
2763                 return candidate->type == target->type;
2764
2765         case MONO_TYPE_PTR:
2766                 return mono_delegate_type_equal (target->data.type, candidate->data.type);
2767
2768         case MONO_TYPE_FNPTR:
2769                 if (candidate->type != MONO_TYPE_FNPTR)
2770                         return FALSE;
2771                 return mono_delegate_signature_equal (mono_type_get_signature (target), mono_type_get_signature (candidate), FALSE);
2772
2773         case MONO_TYPE_GENERICINST: {
2774                 MonoClass *target_klass;
2775                 MonoClass *candidate_klass;
2776                 target_klass = mono_class_from_mono_type (target);
2777                 candidate_klass = mono_class_from_mono_type (candidate);
2778                 /*FIXME handle nullables and enum*/
2779                 return mono_class_is_assignable_from (target_klass, candidate_klass);
2780         }
2781         case MONO_TYPE_OBJECT:
2782                 return MONO_TYPE_IS_REFERENCE (candidate);
2783
2784         case MONO_TYPE_CLASS:
2785                 return mono_class_is_assignable_from(target->data.klass, mono_class_from_mono_type (candidate));
2786
2787         case MONO_TYPE_SZARRAY:
2788                 if (candidate->type != MONO_TYPE_SZARRAY)
2789                         return FALSE;
2790                 return mono_class_is_assignable_from (mono_class_from_mono_type (target)->element_class, mono_class_from_mono_type (candidate)->element_class);
2791
2792         case MONO_TYPE_ARRAY:
2793                 if (candidate->type != MONO_TYPE_ARRAY)
2794                         return FALSE;
2795                 return is_array_type_compatible (target, candidate);
2796
2797         case MONO_TYPE_VALUETYPE:
2798                 /*FIXME handle nullables and enum*/
2799                 return mono_class_from_mono_type (candidate) == mono_class_from_mono_type (target);
2800
2801         case MONO_TYPE_VAR:
2802                 return candidate->type == MONO_TYPE_VAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2803                 return FALSE;
2804
2805         case MONO_TYPE_MVAR:
2806                 return candidate->type == MONO_TYPE_MVAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2807                 return FALSE;
2808
2809         default:
2810                 VERIFIER_DEBUG ( printf ("Unknown type %d. Implement me!\n", target->type); );
2811                 g_assert_not_reached ();
2812                 return FALSE;
2813         }
2814 }
2815
2816 static gboolean
2817 mono_delegate_param_equal (MonoType *delegate, MonoType *method)
2818 {
2819         if (mono_metadata_type_equal_full (delegate, method, TRUE))
2820                 return TRUE;
2821
2822         return mono_delegate_type_equal (method, delegate);
2823 }
2824
2825 static gboolean
2826 mono_delegate_ret_equal (MonoType *delegate, MonoType *method)
2827 {
2828         if (mono_metadata_type_equal_full (delegate, method, TRUE))
2829                 return TRUE;
2830
2831         return mono_delegate_type_equal (delegate, method);
2832 }
2833
2834 /*
2835  * mono_delegate_signature_equal:
2836  * 
2837  * Compare two signatures in the way expected by delegates.
2838  * 
2839  * This function only exists due to the fact that it should ignore the 'has_this' part of the signature.
2840  *
2841  * FIXME can this function be eliminated and proper metadata functionality be used?
2842  */
2843 static gboolean
2844 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn)
2845 {
2846         int i;
2847         int method_offset = is_static_ldftn ? 1 : 0;
2848
2849         if (delegate_sig->param_count + method_offset != method_sig->param_count) 
2850                 return FALSE;
2851
2852         if (delegate_sig->call_convention != method_sig->call_convention)
2853                 return FALSE;
2854
2855         for (i = 0; i < delegate_sig->param_count; i++) { 
2856                 MonoType *p1 = delegate_sig->params [i];
2857                 MonoType *p2 = method_sig->params [i + method_offset];
2858
2859                 if (!mono_delegate_param_equal (p1, p2))
2860                         return FALSE;
2861         }
2862
2863         if (!mono_delegate_ret_equal (delegate_sig->ret, method_sig->ret))
2864                 return FALSE;
2865
2866         return TRUE;
2867 }
2868
2869 /* 
2870  * verify_ldftn_delegate:
2871  * 
2872  * Verify properties of ldftn based delegates.
2873  */
2874 static void
2875 verify_ldftn_delegate (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2876 {
2877         MonoMethod *method = funptr->method;
2878
2879         /*ldftn non-final virtuals only allowed if method is not static,
2880          * the object is a this arg (comes from a ldarg.0), and there is no starg.0.
2881          * This rules doesn't apply if the object on stack is a boxed valuetype.
2882          */
2883         if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !(method->klass->flags & TYPE_ATTRIBUTE_SEALED) && !stack_slot_is_boxed_value (value)) {
2884                 /*A stdarg 0 must not happen, we fail here only in fail fast mode to avoid double error reports*/
2885                 if (IS_FAIL_FAST_MODE (ctx) && ctx->has_this_store)
2886                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at  0x%04x", ctx->ip_offset));
2887
2888                 /*current method must not be static*/
2889                 if (ctx->method->flags & METHOD_ATTRIBUTE_STATIC)
2890                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function at 0x%04x", ctx->ip_offset));
2891
2892                 /*value is the this pointer, loaded using ldarg.0 */
2893                 if (!stack_slot_is_this_pointer (value))
2894                         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));
2895
2896                 ctx->code [ctx->ip_offset].flags |= IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL;
2897         }
2898 }
2899
2900 /*
2901  * verify_delegate_compatibility:
2902  * 
2903  * Verify delegate creation sequence.
2904  * 
2905  */
2906 static void
2907 verify_delegate_compatibility (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2908 {
2909 #define IS_VALID_OPCODE(offset, opcode) (ip [ip_offset - offset] == opcode && (ctx->code [ip_offset - offset].flags & IL_CODE_FLAG_SEEN))
2910 #define IS_LOAD_FUN_PTR(kind) (IS_VALID_OPCODE (6, CEE_PREFIX1) && ip [ip_offset - 5] == kind)
2911
2912         MonoMethod *invoke, *method;
2913         const guint8 *ip = ctx->header->code;
2914         guint32 ip_offset = ctx->ip_offset;
2915         gboolean is_static_ldftn = FALSE, is_first_arg_bound = FALSE;
2916         
2917         if (stack_slot_get_type (funptr) != TYPE_PTR || !funptr->method) {
2918                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid function pointer parameter for delegate constructor at 0x%04x", ctx->ip_offset));
2919                 return;
2920         }
2921         
2922         invoke = mono_get_delegate_invoke (delegate);
2923         method = funptr->method;
2924
2925         is_static_ldftn = (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) && method->flags & METHOD_ATTRIBUTE_STATIC;
2926
2927         if (is_static_ldftn)
2928                 is_first_arg_bound = mono_method_signature (invoke)->param_count + 1 ==  mono_method_signature (method)->param_count;
2929
2930         if (!mono_delegate_signature_equal (mono_method_signature (invoke), mono_method_signature (method), is_first_arg_bound)) {
2931                 char *fun_sig = mono_signature_get_desc (mono_method_signature (method), FALSE);
2932                 char *invoke_sig = mono_signature_get_desc (mono_method_signature (invoke), FALSE);
2933                 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));
2934                 g_free (fun_sig);
2935                 g_free (invoke_sig);
2936         }
2937
2938         /* 
2939          * Delegate code sequences:
2940          * [-6] ldftn token
2941          * newobj ...
2942          * 
2943          * 
2944          * [-7] dup
2945          * [-6] ldvirtftn token
2946          * newobj ...
2947          * 
2948          * ldftn sequence:*/
2949         if (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) {
2950                 verify_ldftn_delegate (ctx, delegate, value, funptr);
2951         } else if (ip_offset > 6 && IS_VALID_OPCODE (7, CEE_DUP) && IS_LOAD_FUN_PTR (CEE_LDVIRTFTN)) {
2952                 ctx->code [ip_offset - 6].flags |= IL_CODE_DELEGATE_SEQUENCE;   
2953         }else {
2954                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid code sequence for delegate creation at 0x%04x", ctx->ip_offset));
2955         }
2956         ctx->code [ip_offset].flags |= IL_CODE_DELEGATE_SEQUENCE;
2957
2958         //general tests
2959         if (is_first_arg_bound) {
2960                 if (!verify_stack_type_compatibility_full (ctx, mono_method_signature (method)->params [0], value, FALSE, TRUE))
2961                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2962         } else {
2963                 if (!verify_stack_type_compatibility_full (ctx, &method->klass->byval_arg, value, FALSE, TRUE) && !stack_slot_is_null_literal (value))
2964                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2965         }
2966
2967         if (stack_slot_get_type (value) != TYPE_COMPLEX)
2968                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid first parameter for delegate creation at 0x%04x", ctx->ip_offset));
2969
2970 #undef IS_VALID_OPCODE
2971 #undef IS_LOAD_FUN_PTR
2972 }
2973
2974 /* implement the opcode checks*/
2975 static void
2976 push_arg (VerifyContext *ctx, unsigned int arg, int take_addr) 
2977 {
2978         ILStackDesc *top;
2979
2980         if (arg >= ctx->max_args) {
2981                 if (take_addr) 
2982                         ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2983                 else {
2984                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2985                         if (check_overflow (ctx)) //FIXME: what sane value could we ever push?
2986                                 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
2987                 }
2988         } else if (check_overflow (ctx)) {
2989                 /*We must let the value be pushed, otherwise we would get an underflow error*/
2990                 check_unverifiable_type (ctx, ctx->params [arg]);
2991                 if (ctx->params [arg]->byref && take_addr)
2992                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2993                 top = stack_push (ctx);
2994                 if (!set_stack_value (ctx, top, ctx->params [arg], take_addr))
2995                         return;
2996
2997                 if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC)) {
2998                         if (take_addr)
2999                                 ctx->has_this_store = TRUE;
3000                         else
3001                                 top->stype |= THIS_POINTER_MASK;
3002                         if (mono_method_is_constructor (ctx->method) && !ctx->super_ctor_called && !ctx->method->klass->valuetype)
3003                                 top->stype |= UNINIT_THIS_MASK;
3004                 }
3005         } 
3006 }
3007
3008 static void
3009 push_local (VerifyContext *ctx, guint32 arg, int take_addr) 
3010 {
3011         if (arg >= ctx->num_locals) {
3012                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local %d", arg + 1));
3013         } else if (check_overflow (ctx)) {
3014                 /*We must let the value be pushed, otherwise we would get an underflow error*/
3015                 check_unverifiable_type (ctx, ctx->locals [arg]);
3016                 if (ctx->locals [arg]->byref && take_addr)
3017                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
3018
3019                 set_stack_value (ctx, stack_push (ctx), ctx->locals [arg], take_addr);
3020         } 
3021 }
3022
3023 static void
3024 store_arg (VerifyContext *ctx, guint32 arg)
3025 {
3026         ILStackDesc *value;
3027
3028         if (arg >= ctx->max_args) {
3029                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", arg + 1, ctx->ip_offset));
3030                 if (check_underflow (ctx, 1))
3031                         stack_pop (ctx);
3032                 return;
3033         }
3034
3035         if (check_underflow (ctx, 1)) {
3036                 value = stack_pop (ctx);
3037                 if (!verify_stack_type_compatibility (ctx, ctx->params [arg], value)) {
3038                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in argument store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3039                 }
3040         }
3041         if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC))
3042                 ctx->has_this_store = 1;
3043 }
3044
3045 static void
3046 store_local (VerifyContext *ctx, guint32 arg)
3047 {
3048         ILStackDesc *value;
3049         if (arg >= ctx->num_locals) {
3050                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", arg + 1, ctx->ip_offset));
3051                 return;
3052         }
3053
3054         /*TODO verify definite assigment */             
3055         if (check_underflow (ctx, 1)) {
3056                 value = stack_pop(ctx);
3057                 if (!verify_stack_type_compatibility (ctx, ctx->locals [arg], value)) {
3058                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type [%s], type [%s] was expected in local store at 0x%04x",
3059                                         stack_slot_get_name (value),
3060                                         mono_type_get_stack_name (ctx->locals [arg]),
3061                                         ctx->ip_offset));       
3062                 }
3063         }
3064 }
3065
3066 /*FIXME add and sub needs special care here*/
3067 static void
3068 do_binop (VerifyContext *ctx, unsigned int opcode, const unsigned char table [TYPE_MAX][TYPE_MAX])
3069 {
3070         ILStackDesc *a, *b, *top;
3071         int idxa, idxb, complexMerge = 0;
3072         unsigned char res;
3073
3074         if (!check_underflow (ctx, 2))
3075                 return;
3076         b = stack_pop (ctx);
3077         a = stack_pop (ctx);
3078
3079         idxa = stack_slot_get_underlying_type (a);
3080         if (stack_slot_is_managed_pointer (a)) {
3081                 idxa = TYPE_PTR;
3082                 complexMerge = 1;
3083         }
3084
3085         idxb = stack_slot_get_underlying_type (b);
3086         if (stack_slot_is_managed_pointer (b)) {
3087                 idxb = TYPE_PTR;
3088                 complexMerge = 2;
3089         }
3090
3091         --idxa;
3092         --idxb;
3093         res = table [idxa][idxb];
3094
3095         VERIFIER_DEBUG ( printf ("binop res %d\n", res); );
3096         VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
3097
3098         top = stack_push (ctx);
3099         if (res == TYPE_INV) {
3100                 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)));
3101                 copy_stack_value (top, a);
3102                 return;
3103         }
3104
3105         if (res & NON_VERIFIABLE_RESULT) {
3106                 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)));
3107
3108                 res = res & ~NON_VERIFIABLE_RESULT;
3109         }
3110
3111         if (complexMerge && res == TYPE_PTR) {
3112                 if (complexMerge == 1) 
3113                         copy_stack_value (top, a);
3114                 else if (complexMerge == 2)
3115                         copy_stack_value (top, b);
3116                 /*
3117                  * There is no need to merge the type of two pointers.
3118                  * The only valid operation is subtraction, that returns a native
3119                  *  int as result and can be used with any 2 pointer kinds.
3120                  * This is valid acording to Patition III 1.1.4
3121                  */
3122         } else
3123                 top->stype = res;
3124         
3125 }
3126
3127
3128 static void
3129 do_boolean_branch_op (VerifyContext *ctx, int delta)
3130 {
3131         int target = ctx->ip_offset + delta;
3132         ILStackDesc *top;
3133
3134         VERIFIER_DEBUG ( printf ("boolean branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
3135  
3136         if (target < 0 || target >= ctx->code_size) {
3137                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Boolean branch target out of code at 0x%04x", ctx->ip_offset));
3138                 return;
3139         }
3140
3141         switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
3142         case 1:
3143                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3144                 break;
3145         case 2:
3146                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3147                 return;
3148         }
3149
3150         ctx->target = target;
3151
3152         if (!check_underflow (ctx, 1))
3153                 return;
3154
3155         top = stack_pop (ctx);
3156         if (!is_valid_bool_arg (top))
3157                 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));
3158
3159         check_unmanaged_pointer (ctx, top);
3160 }
3161
3162 static gboolean
3163 stack_slot_is_complex_type_not_reference_type (ILStackDesc *slot)
3164 {
3165         return stack_slot_get_type (slot) == TYPE_COMPLEX && !MONO_TYPE_IS_REFERENCE (slot->type) && !stack_slot_is_boxed_value (slot);
3166 }
3167
3168 static void
3169 do_branch_op (VerifyContext *ctx, signed int delta, const unsigned char table [TYPE_MAX][TYPE_MAX])
3170 {
3171         ILStackDesc *a, *b;
3172         int idxa, idxb;
3173         unsigned char res;
3174         int target = ctx->ip_offset + delta;
3175
3176         VERIFIER_DEBUG ( printf ("branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
3177  
3178         if (target < 0 || target >= ctx->code_size) {
3179                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
3180                 return;
3181         }
3182
3183         switch (is_valid_cmp_branch_instruction (ctx->header, ctx->ip_offset, target)) {
3184         case 1: /*FIXME use constants and not magic numbers.*/
3185                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3186                 break;
3187         case 2:
3188                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3189                 return;
3190         }
3191
3192         ctx->target = target;
3193
3194         if (!check_underflow (ctx, 2))
3195                 return;
3196
3197         b = stack_pop (ctx);
3198         a = stack_pop (ctx);
3199
3200         idxa = stack_slot_get_underlying_type (a);
3201         if (stack_slot_is_managed_pointer (a))
3202                 idxa = TYPE_PTR;
3203
3204         idxb = stack_slot_get_underlying_type (b);
3205         if (stack_slot_is_managed_pointer (b))
3206                 idxb = TYPE_PTR;
3207
3208         if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
3209                 res = TYPE_INV;
3210         } else {
3211                 --idxa;
3212                 --idxb;
3213                 res = table [idxa][idxb];
3214         }
3215
3216         VERIFIER_DEBUG ( printf ("branch res %d\n", res); );
3217         VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
3218
3219         if (res == TYPE_INV) {
3220                 CODE_NOT_VERIFIABLE (ctx,
3221                         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));
3222         } else if (res & NON_VERIFIABLE_RESULT) {
3223                         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)); 
3224                 res = res & ~NON_VERIFIABLE_RESULT;
3225         }
3226 }
3227
3228 static void
3229 do_cmp_op (VerifyContext *ctx, const unsigned char table [TYPE_MAX][TYPE_MAX], guint32 opcode)
3230 {
3231         ILStackDesc *a, *b;
3232         int idxa, idxb;
3233         unsigned char res;
3234
3235         if (!check_underflow (ctx, 2))
3236                 return;
3237         b = stack_pop (ctx);
3238         a = stack_pop (ctx);
3239
3240         if (opcode == CEE_CGT_UN) {
3241                 if (stack_slot_get_type (a) == TYPE_COMPLEX && stack_slot_get_type (b) == TYPE_COMPLEX) {
3242                         stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3243                         return;
3244                 }
3245         }
3246
3247         idxa = stack_slot_get_underlying_type (a);
3248         if (stack_slot_is_managed_pointer (a))
3249                 idxa = TYPE_PTR;
3250
3251         idxb = stack_slot_get_underlying_type (b);
3252         if (stack_slot_is_managed_pointer (b)) 
3253                 idxb = TYPE_PTR;
3254
3255         if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
3256                 res = TYPE_INV;
3257         } else {
3258                 --idxa;
3259                 --idxb;
3260                 res = table [idxa][idxb];
3261         }
3262
3263         if(res == TYPE_INV) {
3264                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf("Compare 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));
3265         } else if (res & NON_VERIFIABLE_RESULT) {
3266                 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)); 
3267                 res = res & ~NON_VERIFIABLE_RESULT;
3268         }
3269         stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3270 }
3271
3272 static void
3273 do_ret (VerifyContext *ctx)
3274 {
3275         MonoType *ret = ctx->signature->ret;
3276         VERIFIER_DEBUG ( printf ("checking ret\n"); );
3277         if (ret->type != MONO_TYPE_VOID) {
3278                 ILStackDesc *top;
3279                 if (!check_underflow (ctx, 1))
3280                         return;
3281
3282                 top = stack_pop(ctx);
3283
3284                 if (!verify_stack_type_compatibility (ctx, ctx->signature->ret, top)) {
3285                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible return value on stack with method signature ret at 0x%04x", ctx->ip_offset));
3286                         return;
3287                 }
3288
3289                 if (ret->byref || ret->type == MONO_TYPE_TYPEDBYREF || mono_type_is_value_type (ret, "System", "ArgIterator") || mono_type_is_value_type (ret, "System", "RuntimeArgumentHandle"))
3290                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method returns byref, TypedReference, ArgIterator or RuntimeArgumentHandle at 0x%04x", ctx->ip_offset));
3291         }
3292
3293         if (ctx->eval.size > 0) {
3294                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack not empty (%d) after ret at 0x%04x", ctx->eval.size, ctx->ip_offset));
3295         } 
3296         if (in_any_block (ctx->header, ctx->ip_offset))
3297                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ret cannot escape exception blocks at 0x%04x", ctx->ip_offset));
3298 }
3299
3300 /*
3301  * 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.
3302  *      This is illegal but mono_get_method_full decoded it.
3303  * TODO handle calling .ctor outside one or calling the .ctor for other class but super  
3304  */
3305 static void
3306 do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual)
3307 {
3308         int param_count, i;
3309         MonoMethodSignature *sig;
3310         ILStackDesc *value;
3311         MonoMethod *method;
3312         gboolean virt_check_this = FALSE;
3313         gboolean constrained = ctx->prefix_set & PREFIX_CONSTRAINED;
3314
3315         if (!(method = verifier_load_method (ctx, method_token, virtual ? "callvirt" : "call")))
3316                 return;
3317
3318         if (virtual) {
3319                 CLEAR_PREFIX (ctx, PREFIX_CONSTRAINED);
3320
3321                 if (method->klass->valuetype) // && !constrained ???
3322                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with valuetype method at 0x%04x", ctx->ip_offset));
3323
3324                 if ((method->flags & METHOD_ATTRIBUTE_STATIC))
3325                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with static method at 0x%04x", ctx->ip_offset));
3326
3327         } else {
3328                 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT) 
3329                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use call with an abstract method at 0x%04x", ctx->ip_offset));
3330                 
3331                 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL)) {
3332                         virt_check_this = TRUE;
3333                         ctx->code [ctx->ip_offset].flags |= IL_CODE_CALL_NONFINAL_VIRTUAL;
3334                 }
3335         }
3336
3337         if (!(sig = mono_method_get_signature_full (method, ctx->image, method_token, ctx->generic_context)))
3338                 sig = mono_method_get_signature (method, ctx->image, method_token);
3339
3340         param_count = sig->param_count + sig->hasthis;
3341         if (!check_underflow (ctx, param_count))
3342                 return;
3343
3344         for (i = sig->param_count - 1; i >= 0; --i) {
3345                 VERIFIER_DEBUG ( printf ("verifying argument %d\n", i); );
3346                 value = stack_pop (ctx);
3347                 if (!verify_stack_type_compatibility (ctx, sig->params[i], value)) {
3348                         char *stack_name = stack_slot_full_name (value);
3349                         char *sig_name = mono_type_full_name (sig->params [i]);
3350                         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));
3351                         g_free (stack_name);
3352                         g_free (sig_name);
3353                 }
3354
3355                 if (stack_slot_is_managed_mutability_pointer (value))
3356                         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));
3357
3358                 if ((ctx->prefix_set & PREFIX_TAIL) && stack_slot_is_managed_pointer (value)) {
3359                         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));
3360                         return;
3361                 }
3362         }
3363
3364         if (sig->hasthis) {
3365                 MonoType *type = &method->klass->byval_arg;
3366                 ILStackDesc copy;
3367
3368                 if (mono_method_is_constructor (method) && !method->klass->valuetype) {
3369                         if (!mono_method_is_constructor (ctx->method))
3370                                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor outside one at 0x%04x", ctx->ip_offset));
3371                         if (method->klass != ctx->method->klass->parent && method->klass != ctx->method->klass)
3372                                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor to a type diferent that this or super at 0x%04x", ctx->ip_offset));
3373
3374                         ctx->super_ctor_called = TRUE;
3375                         value = stack_pop_safe (ctx);
3376                         if ((value->stype & THIS_POINTER_MASK) != THIS_POINTER_MASK)
3377                                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid 'this ptr' argument for constructor at 0x%04x", ctx->ip_offset));
3378                 } else {
3379                         value = stack_pop (ctx);
3380                 }
3381                         
3382                 copy_stack_value (&copy, value);
3383                 //TODO we should extract this to a 'drop_byref_argument' and use everywhere
3384                 //Other parts of the code suffer from the same issue of 
3385                 copy.type = mono_type_get_type_byval (copy.type);
3386                 copy.stype &= ~POINTER_MASK;
3387
3388                 if (virt_check_this && !stack_slot_is_this_pointer (value) && !(method->klass->valuetype || stack_slot_is_boxed_value (value)))
3389                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a non-final virtual method from an objet diferent thant the this pointer at 0x%04x", ctx->ip_offset));
3390
3391                 if (constrained && virtual) {
3392                         if (!stack_slot_is_managed_pointer (value))
3393                                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object is not a managed pointer for a constrained call at 0x%04x", ctx->ip_offset));
3394                         if (!mono_metadata_type_equal_full (mono_type_get_type_byval (value->type), ctx->constrained_type, TRUE))
3395                                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object not compatible with constrained type at 0x%04x", ctx->ip_offset));
3396                         copy.stype |= BOXED_MASK;
3397                 } else {
3398                         if (stack_slot_is_managed_pointer (value) && !mono_class_from_mono_type (value->type)->valuetype)
3399                                 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));
3400         
3401                         if (!virtual && mono_class_from_mono_type (value->type)->valuetype && !method->klass->valuetype && !stack_slot_is_boxed_value (value))
3402                                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a valuetype baseclass at 0x%04x", ctx->ip_offset));
3403         
3404                         if (virtual && mono_class_from_mono_type (value->type)->valuetype && !stack_slot_is_boxed_value (value))
3405                                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a valuetype with callvirt at 0x%04x", ctx->ip_offset));
3406         
3407                         if (method->klass->valuetype && (stack_slot_is_boxed_value (value) || !stack_slot_is_managed_pointer (value)))
3408                                 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));
3409                 }
3410                 if (!verify_stack_type_compatibility (ctx, type, &copy))
3411                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible this argument on stack with method signature at 0x%04x", ctx->ip_offset));
3412
3413                 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, mono_class_from_mono_type (value->type))) {
3414                         char *name = mono_method_full_name (method, TRUE);
3415                         CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3416                         g_free (name);
3417                 }
3418
3419         } else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
3420                 char *name = mono_method_full_name (method, TRUE);
3421                 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3422                 g_free (name);
3423         }
3424
3425         if (sig->ret->type != MONO_TYPE_VOID) {
3426                 if (check_overflow (ctx)) {
3427                         value = stack_push (ctx);
3428                         set_stack_value (ctx, value, sig->ret, FALSE);
3429                         if ((ctx->prefix_set & PREFIX_READONLY) && method->klass->rank && !strcmp (method->name, "Address")) {
3430                                 ctx->prefix_set &= ~PREFIX_READONLY;
3431                                 value->stype |= CMMP_MASK;
3432                         }
3433                 }
3434         }
3435
3436         if ((ctx->prefix_set & PREFIX_TAIL)) {
3437                 if (!mono_delegate_ret_equal (mono_method_signature (ctx->method)->ret, sig->ret))
3438                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call with incompatible return type at 0x%04x", ctx->ip_offset));
3439                 if (ctx->header->code [ctx->ip_offset + 5] != CEE_RET)
3440                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call not followed by ret at 0x%04x", ctx->ip_offset));
3441         }
3442
3443 }
3444
3445 static void
3446 do_push_static_field (VerifyContext *ctx, int token, gboolean take_addr)
3447 {
3448         MonoClassField *field;
3449         MonoClass *klass;
3450         if (!take_addr)
3451                 CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3452
3453         if (!(field = verifier_load_field (ctx, token, &klass, take_addr ? "ldsflda" : "ldsfld")))
3454                 return;
3455
3456         if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) { 
3457                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load non static field at 0x%04x", ctx->ip_offset));
3458                 return;
3459         }
3460         /*taking the address of initonly field only works from the static constructor */
3461         if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3462                 !(field->parent == ctx->method->klass && (ctx->method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_STATIC)) && !strcmp (".cctor", ctx->method->name)))
3463                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
3464
3465         if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3466                 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3467
3468         set_stack_value (ctx, stack_push (ctx), field->type, take_addr);
3469 }
3470
3471 static void
3472 do_store_static_field (VerifyContext *ctx, int token) {
3473         MonoClassField *field;
3474         MonoClass *klass;
3475         ILStackDesc *value;
3476         CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3477
3478         if (!check_underflow (ctx, 1))
3479                 return;
3480
3481         value = stack_pop (ctx);
3482
3483         if (!(field = verifier_load_field (ctx, token, &klass, "stsfld")))
3484                 return;
3485
3486         if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) { 
3487                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store non static field at 0x%04x", ctx->ip_offset));
3488                 return;
3489         }
3490
3491         if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3492                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type in store static field at 0x%04x", ctx->ip_offset));
3493                 return;
3494         }
3495
3496         if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3497                 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3498
3499         if (!verify_stack_type_compatibility (ctx, field->type, value))
3500                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in static field store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));       
3501 }
3502
3503 static gboolean
3504 check_is_valid_type_for_field_ops (VerifyContext *ctx, int token, ILStackDesc *obj, MonoClassField **ret_field, const char *opcode)
3505 {
3506         MonoClassField *field;
3507         MonoClass *klass;
3508         gboolean is_pointer;
3509
3510         /*must be a reference type, a managed pointer, an unamanaged pointer, or a valuetype*/
3511         if (!(field = verifier_load_field (ctx, token, &klass, opcode)))
3512                 return FALSE;
3513
3514         *ret_field = field;
3515         //the value on stack is going to be used as a pointer
3516         is_pointer = stack_slot_get_type (obj) == TYPE_PTR || (stack_slot_get_type (obj) == TYPE_NATIVE_INT && !get_stack_type (&field->parent->byval_arg));
3517
3518         if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3519                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type at 0x%04x", ctx->ip_offset));
3520                 return FALSE;
3521         }
3522         g_assert (obj->type);
3523
3524         /*The value on the stack must be a subclass of the defining type of the field*/ 
3525         /* we need to check if we can load the field from the stack value*/
3526         if (is_pointer) {
3527                 if (stack_slot_get_underlying_type (obj) == TYPE_NATIVE_INT)
3528                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Native int is not a verifiable type to reference a field at 0x%04x", ctx->ip_offset));
3529
3530                 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3531                                 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3532         } else {
3533                 if (!field->parent->valuetype && stack_slot_is_managed_pointer (obj))
3534                         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));
3535
3536                 /*a value type can be loaded from a value or a managed pointer, but not a boxed object*/
3537                 if (field->parent->valuetype && stack_slot_is_boxed_value (obj))
3538                         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));
3539
3540                 if (!stack_slot_is_null_literal (obj) && !verify_stack_type_compatibility_full (ctx, &field->parent->byval_arg, obj, TRUE, FALSE))
3541                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not compatible to reference the field at 0x%04x", ctx->ip_offset));
3542
3543                 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, mono_class_from_mono_type (obj->type)))
3544                         CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3545         } 
3546
3547         check_unmanaged_pointer (ctx, obj);
3548         return TRUE;
3549 }
3550
3551 static void
3552 do_push_field (VerifyContext *ctx, int token, gboolean take_addr)
3553 {
3554         ILStackDesc *obj;
3555         MonoClassField *field;
3556
3557         if (!take_addr)
3558                 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3559
3560         if (!check_underflow (ctx, 1))
3561                 return;
3562         obj = stack_pop_safe (ctx);
3563
3564         if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, take_addr ? "ldflda" : "ldfld"))
3565                 return;
3566
3567         if (take_addr && field->parent->valuetype && !stack_slot_is_managed_pointer (obj))
3568                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a temporary value-type at 0x%04x", ctx->ip_offset));
3569
3570         if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3571                 !(field->parent == ctx->method->klass && mono_method_is_constructor (ctx->method)))
3572                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
3573
3574         set_stack_value (ctx, stack_push (ctx), field->type, take_addr);
3575 }
3576
3577 static void
3578 do_store_field (VerifyContext *ctx, int token)
3579 {
3580         ILStackDesc *value, *obj;
3581         MonoClassField *field;
3582         CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3583
3584         if (!check_underflow (ctx, 2))
3585                 return;
3586
3587         value = stack_pop (ctx);
3588         obj = stack_pop_safe (ctx);
3589
3590         if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, "stfld"))
3591                 return;
3592
3593         if (!verify_stack_type_compatibility (ctx, field->type, value))
3594                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in field store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));      
3595 }
3596
3597 /*TODO proper handle for Nullable<T>*/
3598 static void
3599 do_box_value (VerifyContext *ctx, int klass_token)
3600 {
3601         ILStackDesc *value;
3602         MonoType *type = get_boxable_mono_type (ctx, klass_token, "box");
3603         MonoClass *klass;       
3604
3605         if (!type)
3606                 return;
3607
3608         if (!check_underflow (ctx, 1))
3609                 return;
3610
3611         value = stack_pop (ctx);
3612         /*box is a nop for reference types*/
3613
3614         if (stack_slot_get_underlying_type (value) == TYPE_COMPLEX && MONO_TYPE_IS_REFERENCE (value->type) && MONO_TYPE_IS_REFERENCE (type)) {
3615                 stack_push_stack_val (ctx, value)->stype |= BOXED_MASK;
3616                 return;
3617         }
3618
3619
3620         if (!verify_stack_type_compatibility (ctx, type, value))
3621                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for boxing operation at 0x%04x", ctx->ip_offset));
3622
3623         klass = mono_class_from_mono_type (type);
3624         if (mono_class_is_nullable (klass))
3625                 type = &mono_class_get_nullable_param (klass)->byval_arg;
3626         stack_push_val (ctx, TYPE_COMPLEX | BOXED_MASK, type);
3627 }
3628
3629 static void
3630 do_unbox_value (VerifyContext *ctx, int klass_token)
3631 {
3632         ILStackDesc *value;
3633         MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox");
3634
3635         if (!type)
3636                 return;
3637  
3638         if (!check_underflow (ctx, 1))
3639                 return;
3640
3641         if (!mono_class_from_mono_type (type)->valuetype)
3642                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid reference type for unbox at 0x%04x", ctx->ip_offset));
3643
3644         value = stack_pop (ctx);
3645
3646         /*Value should be: a boxed valuetype or a reference type*/
3647         if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3648                 (stack_slot_is_boxed_value (value) || !mono_class_from_mono_type (value->type)->valuetype)))
3649                 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));
3650
3651         set_stack_value (ctx, value = stack_push (ctx), mono_type_get_type_byref (type), FALSE);
3652         value->stype |= CMMP_MASK;
3653 }
3654
3655 static void
3656 do_unbox_any (VerifyContext *ctx, int klass_token)
3657 {
3658         ILStackDesc *value;
3659         MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox.any");
3660
3661         if (!type)
3662                 return;
3663  
3664         if (!check_underflow (ctx, 1))
3665                 return;
3666
3667         value = stack_pop (ctx);
3668
3669         /*Value should be: a boxed valuetype or a reference type*/
3670         if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3671                 (stack_slot_is_boxed_value (value) || !mono_class_from_mono_type (value->type)->valuetype)))
3672                 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));
3673  
3674         set_stack_value (ctx, stack_push (ctx), type, FALSE);
3675 }
3676
3677 static void
3678 do_unary_math_op (VerifyContext *ctx, int op)
3679 {
3680         ILStackDesc *value;
3681         if (!check_underflow (ctx, 1))
3682                 return;
3683         value = stack_pop (ctx);
3684         switch (stack_slot_get_type (value)) {
3685         case TYPE_I4:
3686         case TYPE_I8:
3687         case TYPE_NATIVE_INT:
3688                 break;
3689         case TYPE_R8:
3690                 if (op == CEE_NEG)
3691                         break;
3692         case TYPE_COMPLEX: /*only enums are ok*/
3693                 if (mono_type_is_enum_type (value->type))
3694                         break;
3695         default:
3696                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for unary not at 0x%04x", ctx->ip_offset));
3697         }
3698         stack_push_stack_val (ctx, value);
3699 }
3700
3701 static void
3702 do_conversion (VerifyContext *ctx, int kind) 
3703 {
3704         ILStackDesc *value;
3705         if (!check_underflow (ctx, 1))
3706                 return;
3707         value = stack_pop (ctx);
3708
3709         switch (stack_slot_get_type (value)) {
3710         case TYPE_I4:
3711         case TYPE_I8:
3712         case TYPE_NATIVE_INT:
3713         case TYPE_R8:
3714                 break;
3715         default:
3716                 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));
3717         }
3718
3719         switch (kind) {
3720         case TYPE_I4:
3721                 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3722                 break;
3723         case TYPE_I8:
3724                 stack_push_val (ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
3725                 break;
3726         case TYPE_R8:
3727                 stack_push_val (ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
3728                 break;
3729         case TYPE_NATIVE_INT:
3730                 stack_push_val (ctx, TYPE_NATIVE_INT, &mono_defaults.int_class->byval_arg);
3731                 break;
3732         default:
3733                 g_error ("unknown type %02x in conversion", kind);
3734
3735         }
3736 }
3737
3738 static void
3739 do_load_token (VerifyContext *ctx, int token) 
3740 {
3741         gpointer handle;
3742         MonoClass *handle_class;
3743         if (!check_overflow (ctx))
3744                 return;
3745         handle = mono_ldtoken (ctx->image, token, &handle_class, ctx->generic_context);
3746         if (!handle) {
3747                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid token 0x%x for ldtoken at 0x%04x", token, ctx->ip_offset));
3748                 return;
3749         }
3750         if (handle_class == mono_defaults.typehandle_class) {
3751                 mono_type_is_valid_in_context (ctx, (MonoType*)handle);
3752         } else if (handle_class == mono_defaults.methodhandle_class) {
3753                 mono_method_is_valid_in_context (ctx, (MonoMethod*)handle);             
3754         } else if (handle_class == mono_defaults.fieldhandle_class) {
3755                 mono_type_is_valid_in_context (ctx, &((MonoClassField*)handle)->parent->byval_arg);                             
3756         } else {
3757                 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid ldtoken type %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
3758         }
3759         stack_push_val (ctx, TYPE_COMPLEX, mono_class_get_type (handle_class));
3760 }
3761
3762 static void
3763 do_ldobj_value (VerifyContext *ctx, int token) 
3764 {
3765         ILStackDesc *value;
3766         MonoType *type = get_boxable_mono_type (ctx, token, "ldobj");
3767         CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3768
3769         if (!type)
3770                 return;
3771
3772         if (!check_underflow (ctx, 1))
3773                 return;
3774
3775         value = stack_pop (ctx);
3776         if (!stack_slot_is_managed_pointer (value) 
3777                         && stack_slot_get_type (value) != TYPE_NATIVE_INT
3778                         && !(stack_slot_get_type (value) == TYPE_PTR && value->type->type != MONO_TYPE_FNPTR)) {
3779                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid argument %s to ldobj at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3780                 return;
3781         }
3782
3783         if (stack_slot_get_type (value) == TYPE_NATIVE_INT)
3784                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Using native pointer to ldobj at 0x%04x", ctx->ip_offset));
3785
3786         /*We have a byval on the stack, but the comparison must be strict. */
3787         if (!verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (value->type), TRUE))
3788                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldojb operation at 0x%04x", ctx->ip_offset));
3789
3790         set_stack_value (ctx, stack_push (ctx), type, FALSE);
3791 }
3792
3793 static void
3794 do_stobj (VerifyContext *ctx, int token) 
3795 {
3796         ILStackDesc *dest, *src;
3797         MonoType *type = get_boxable_mono_type (ctx, token, "stobj");
3798         CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3799
3800         if (!type)
3801                 return;
3802
3803         if (!check_underflow (ctx, 2))
3804                 return;
3805
3806         src = stack_pop (ctx);
3807         dest = stack_pop (ctx);
3808
3809         if (stack_slot_is_managed_mutability_pointer (dest))
3810                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stobj at 0x%04x", ctx->ip_offset));
3811
3812         if (!stack_slot_is_managed_pointer (dest)) 
3813                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of stobj operation at 0x%04x", ctx->ip_offset));
3814
3815         if (stack_slot_is_boxed_value (src) && !MONO_TYPE_IS_REFERENCE (src->type) && !MONO_TYPE_IS_REFERENCE (type))
3816                 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));
3817
3818         if (!verify_stack_type_compatibility (ctx, type, src))
3819                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Token and source types of stobj don't match at 0x%04x", ctx->ip_offset));
3820
3821         if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3822                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of stobj don't match at 0x%04x", ctx->ip_offset));
3823 }
3824
3825 static void
3826 do_cpobj (VerifyContext *ctx, int token)
3827 {
3828         ILStackDesc *dest, *src;
3829         MonoType *type = get_boxable_mono_type (ctx, token, "cpobj");
3830         if (!type)
3831                 return;
3832
3833         if (!check_underflow (ctx, 2))
3834                 return;
3835
3836         src = stack_pop (ctx);
3837         dest = stack_pop (ctx);
3838
3839         if (!stack_slot_is_managed_pointer (src)) 
3840                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid source of cpobj operation at 0x%04x", ctx->ip_offset));
3841
3842         if (!stack_slot_is_managed_pointer (dest)) 
3843                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of cpobj operation at 0x%04x", ctx->ip_offset));
3844
3845         if (stack_slot_is_managed_mutability_pointer (dest))
3846                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with cpobj at 0x%04x", ctx->ip_offset));
3847
3848         if (!verify_type_compatibility (ctx, type, mono_type_get_type_byval (src->type)))
3849                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Token and source types of cpobj don't match at 0x%04x", ctx->ip_offset));
3850
3851         if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3852                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of cpobj don't match at 0x%04x", ctx->ip_offset));
3853 }
3854
3855 static void
3856 do_initobj (VerifyContext *ctx, int token)
3857 {
3858         ILStackDesc *obj;
3859         MonoType *stack, *type = get_boxable_mono_type (ctx, token, "initobj");
3860         if (!type)
3861                 return;
3862
3863         if (!check_underflow (ctx, 1))
3864                 return;
3865
3866         obj = stack_pop (ctx);
3867
3868         if (!stack_slot_is_managed_pointer (obj)) 
3869                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid object address for initobj at 0x%04x", ctx->ip_offset));
3870
3871         if (stack_slot_is_managed_mutability_pointer (obj))
3872                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with initobj at 0x%04x", ctx->ip_offset));
3873
3874         stack = mono_type_get_type_byval (obj->type);
3875         if (MONO_TYPE_IS_REFERENCE (stack)) {
3876                 if (!verify_type_compatibility (ctx, stack, type)) 
3877                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3878                 else if (IS_STRICT_MODE (ctx) && !mono_metadata_type_equal (type, stack)) 
3879                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3880         } else if (!verify_type_compatibility (ctx, stack, type)) {
3881                 char *expected_name = mono_type_full_name (type);
3882                 char *stack_name = mono_type_full_name (stack);
3883
3884                 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));
3885                 g_free (expected_name);
3886                 g_free (stack_name);
3887         }
3888 }
3889
3890 static void
3891 do_newobj (VerifyContext *ctx, int token) 
3892 {
3893         ILStackDesc *value;
3894         int i;
3895         MonoMethodSignature *sig;
3896         MonoMethod *method;
3897         gboolean is_delegate = FALSE;
3898
3899         if (!(method = verifier_load_method (ctx, token, "newobj")))
3900                 return;
3901
3902         if (!mono_method_is_constructor (method)) {
3903                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method from token 0x%08x not a constructor at 0x%04x", token, ctx->ip_offset));
3904                 return;
3905         }
3906
3907         if (method->klass->flags & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE))
3908                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Trying to instantiate an abstract or interface type at 0x%04x", ctx->ip_offset));
3909
3910         if (!mono_method_can_access_method_full (ctx->method, method, NULL)) {
3911                 char *from = mono_method_full_name (ctx->method, TRUE);
3912                 char *to = mono_method_full_name (method, TRUE);
3913                 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);
3914                 g_free (from);
3915                 g_free (to);
3916         }
3917
3918         //FIXME use mono_method_get_signature_full
3919         sig = mono_method_signature (method);
3920         if (!check_underflow (ctx, sig->param_count))
3921                 return;
3922
3923         is_delegate = method->klass->parent == mono_defaults.multicastdelegate_class;
3924
3925         if (is_delegate) {
3926                 ILStackDesc *funptr;
3927                 //first arg is object, second arg is fun ptr
3928                 if (sig->param_count != 2) {
3929                         ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid delegate constructor at 0x%04x", ctx->ip_offset));
3930                         return;
3931                 }
3932                 funptr = stack_pop (ctx);
3933                 value = stack_pop (ctx);
3934                 verify_delegate_compatibility (ctx, method->klass, value, funptr);
3935         } else {
3936                 for (i = sig->param_count - 1; i >= 0; --i) {
3937                         VERIFIER_DEBUG ( printf ("verifying constructor argument %d\n", i); );
3938                         value = stack_pop (ctx);
3939                         if (!verify_stack_type_compatibility (ctx, sig->params [i], value)) {
3940                                 char *stack_name = stack_slot_full_name (value);
3941                                 char *sig_name = mono_type_full_name (sig->params [i]);
3942                                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible parameter value with constructor signature: %s X %s at 0x%04x", sig_name, stack_name, ctx->ip_offset));
3943                                 g_free (stack_name);
3944                                 g_free (sig_name);
3945                         }
3946
3947                         if (stack_slot_is_managed_mutability_pointer (value))
3948                                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer as argument of newobj at 0x%04x", ctx->ip_offset));
3949                 }
3950         }
3951
3952         if (check_overflow (ctx))
3953                 set_stack_value (ctx, stack_push (ctx),  &method->klass->byval_arg, FALSE);
3954 }
3955
3956 static void
3957 do_cast (VerifyContext *ctx, int token, const char *opcode) {
3958         ILStackDesc *value;
3959         MonoType *type;
3960         gboolean is_boxed;
3961         gboolean do_box;
3962
3963         if (!check_underflow (ctx, 1))
3964                 return;
3965
3966         if (!(type = verifier_load_type (ctx, token, opcode)))
3967                 return;
3968
3969         if (type->byref) {
3970                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid %s type at 0x%04x", opcode, ctx->ip_offset));
3971                 return;
3972         }
3973
3974         value = stack_pop (ctx);
3975         is_boxed = stack_slot_is_boxed_value (value);
3976
3977         if (stack_slot_is_managed_pointer (value))
3978                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
3979         else if (!MONO_TYPE_IS_REFERENCE  (value->type) && !is_boxed) {
3980                 char *name = stack_slot_full_name (value);
3981                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Expected a reference type on stack for %s but found %s at 0x%04x", opcode, name, ctx->ip_offset));
3982                 g_free (name);
3983         }
3984
3985         switch (value->type->type) {
3986         case MONO_TYPE_FNPTR:
3987         case MONO_TYPE_PTR:
3988         case MONO_TYPE_TYPEDBYREF: 
3989                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
3990         }
3991
3992         do_box = is_boxed || mono_type_is_generic_argument(type) || mono_class_from_mono_type (type)->valuetype;
3993         stack_push_val (ctx, TYPE_COMPLEX | (do_box ? BOXED_MASK : 0), type);
3994 }
3995
3996 static MonoType *
3997 mono_type_from_opcode (int opcode) {
3998         switch (opcode) {
3999         case CEE_LDIND_I1:
4000         case CEE_LDIND_U1:
4001         case CEE_STIND_I1:
4002         case CEE_LDELEM_I1:
4003         case CEE_LDELEM_U1:
4004         case CEE_STELEM_I1:
4005                 return &mono_defaults.sbyte_class->byval_arg;
4006
4007         case CEE_LDIND_I2:
4008         case CEE_LDIND_U2:
4009         case CEE_STIND_I2:
4010         case CEE_LDELEM_I2:
4011         case CEE_LDELEM_U2:
4012         case CEE_STELEM_I2:
4013                 return &mono_defaults.int16_class->byval_arg;
4014
4015         case CEE_LDIND_I4:
4016         case CEE_LDIND_U4:
4017         case CEE_STIND_I4:
4018         case CEE_LDELEM_I4:
4019         case CEE_LDELEM_U4:
4020         case CEE_STELEM_I4:
4021                 return &mono_defaults.int32_class->byval_arg;
4022
4023         case CEE_LDIND_I8:
4024         case CEE_STIND_I8:
4025         case CEE_LDELEM_I8:
4026         case CEE_STELEM_I8:
4027                 return &mono_defaults.int64_class->byval_arg;
4028
4029         case CEE_LDIND_R4:
4030         case CEE_STIND_R4:
4031         case CEE_LDELEM_R4:
4032         case CEE_STELEM_R4:
4033                 return &mono_defaults.single_class->byval_arg;
4034
4035         case CEE_LDIND_R8:
4036         case CEE_STIND_R8:
4037         case CEE_LDELEM_R8:
4038         case CEE_STELEM_R8:
4039                 return &mono_defaults.double_class->byval_arg;
4040
4041         case CEE_LDIND_I:
4042         case CEE_STIND_I:
4043         case CEE_LDELEM_I:
4044         case CEE_STELEM_I:
4045                 return &mono_defaults.int_class->byval_arg;
4046
4047         case CEE_LDIND_REF:
4048         case CEE_STIND_REF:
4049         case CEE_LDELEM_REF:
4050         case CEE_STELEM_REF:
4051                 return &mono_defaults.object_class->byval_arg;
4052
4053         default:
4054                 g_error ("unknown opcode %02x in mono_type_from_opcode ", opcode);
4055                 return NULL;
4056         }
4057 }
4058
4059 static void
4060 do_load_indirect (VerifyContext *ctx, int opcode)
4061 {
4062         ILStackDesc *value;
4063         CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
4064
4065         if (!check_underflow (ctx, 1))
4066                 return;
4067         
4068         value = stack_pop (ctx);
4069         if (!stack_slot_is_managed_pointer (value)) {
4070                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Load indirect not using a manager pointer at 0x%04x", ctx->ip_offset));
4071                 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
4072                 return;
4073         }
4074
4075         if (opcode == CEE_LDIND_REF) {
4076                 if (stack_slot_get_underlying_type (value) != TYPE_COMPLEX || mono_class_from_mono_type (value->type)->valuetype)
4077                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind_ref expected object byref operation at 0x%04x", ctx->ip_offset));
4078                 set_stack_value (ctx, stack_push (ctx), mono_type_get_type_byval (value->type), FALSE);
4079         } else {
4080                 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (value->type), TRUE))
4081                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4082                 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
4083         }
4084 }
4085
4086 static void
4087 do_store_indirect (VerifyContext *ctx, int opcode)
4088 {
4089         ILStackDesc *addr, *val;
4090         CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
4091
4092         if (!check_underflow (ctx, 2))
4093                 return;
4094
4095         val = stack_pop (ctx);
4096         addr = stack_pop (ctx); 
4097
4098         check_unmanaged_pointer (ctx, addr);
4099
4100         if (!stack_slot_is_managed_pointer (addr) && stack_slot_get_type (addr) != TYPE_PTR) {
4101                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid non-pointer argument to stind at 0x%04x", ctx->ip_offset));
4102                 return;
4103         }
4104
4105         if (stack_slot_is_managed_mutability_pointer (addr)) {
4106                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stind at 0x%04x", ctx->ip_offset));
4107                 return;
4108         }
4109
4110         if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (addr->type), TRUE))
4111                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid addr type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4112
4113         if (!verify_stack_type_compatibility (ctx, mono_type_from_opcode (opcode), val))
4114                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4115 }
4116
4117 static void
4118 do_newarr (VerifyContext *ctx, int token) 
4119 {
4120         ILStackDesc *value;
4121         MonoType *type = get_boxable_mono_type (ctx, token, "newarr");
4122
4123         if (!type)
4124                 return;
4125
4126         if (!check_underflow (ctx, 1))
4127                 return;
4128
4129         value = stack_pop (ctx);
4130         if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
4131                 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));
4132
4133         set_stack_value (ctx, stack_push (ctx), mono_class_get_type (mono_array_class_get (mono_class_from_mono_type (type), 1)), FALSE);
4134 }
4135
4136 /*FIXME handle arrays that are not 0-indexed*/
4137 static void
4138 do_ldlen (VerifyContext *ctx)
4139 {
4140         ILStackDesc *value;
4141
4142         if (!check_underflow (ctx, 1))
4143                 return;
4144
4145         value = stack_pop (ctx);
4146
4147         if (stack_slot_get_type (value) != TYPE_COMPLEX || value->type->type != MONO_TYPE_SZARRAY)
4148                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type for ldlen at 0x%04x", ctx->ip_offset));
4149
4150         stack_push_val (ctx, TYPE_NATIVE_INT, &mono_defaults.int_class->byval_arg);     
4151 }
4152
4153 /*FIXME handle arrays that are not 0-indexed*/
4154 /*FIXME handle readonly prefix and CMMP*/
4155 static void
4156 do_ldelema (VerifyContext *ctx, int klass_token)
4157 {
4158         ILStackDesc *index, *array, *res;
4159         MonoType *type = get_boxable_mono_type (ctx, klass_token, "ldelema");
4160         gboolean valid; 
4161
4162         if (!type)
4163                 return;
4164
4165         if (!check_underflow (ctx, 2))
4166                 return;
4167
4168         index = stack_pop (ctx);
4169         array = stack_pop (ctx);
4170
4171         if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4172                 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));
4173
4174         if (!stack_slot_is_null_literal (array)) {
4175                 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
4176                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type(%s) for ldelema at 0x%04x", stack_slot_get_name (array), ctx->ip_offset));
4177                 else {
4178                         if (get_stack_type (type) == TYPE_I4 || get_stack_type (type) == TYPE_NATIVE_INT) {
4179                                         valid = verify_type_compatibility_full (ctx, type, &array->type->data.klass->byval_arg, TRUE);
4180                         } else {
4181                                 valid = mono_metadata_type_equal (type, &array->type->data.klass->byval_arg);
4182                         }
4183                         if (!valid)
4184                                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelema at 0x%04x", ctx->ip_offset));
4185                 }
4186         }
4187
4188         res = stack_push (ctx);
4189         set_stack_value (ctx, res, type, TRUE);
4190         if (ctx->prefix_set & PREFIX_READONLY) {
4191                 ctx->prefix_set &= ~PREFIX_READONLY;
4192                 res->stype |= CMMP_MASK;
4193         }
4194 }
4195
4196 /*
4197  * FIXME handle arrays that are not 0-indexed
4198  * FIXME handle readonly prefix and CMMP
4199  */
4200 static void
4201 do_ldelem (VerifyContext *ctx, int opcode, int token)
4202 {
4203 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
4204         ILStackDesc *index, *array;
4205         MonoType *type;
4206         if (!check_underflow (ctx, 2))
4207                 return;
4208
4209         if (opcode == CEE_LDELEM) {
4210                 if (!(type = verifier_load_type (ctx, token, "ldelem.any"))) {
4211                         ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
4212                         return;
4213                 }
4214         } else {
4215                 type = mono_type_from_opcode (opcode);
4216         }
4217
4218         index = stack_pop (ctx);
4219         array = stack_pop (ctx);
4220
4221         if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4222                 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));
4223
4224         if (!stack_slot_is_null_literal (array)) {
4225                 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
4226                         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));
4227                 else {
4228                         if (opcode == CEE_LDELEM_REF) {
4229                                 if (array->type->data.klass->valuetype)
4230                                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for ldelem.ref 0x%04x", ctx->ip_offset));
4231                                 type = &array->type->data.klass->byval_arg;
4232                         } else {
4233                                 MonoType *candidate = &array->type->data.klass->byval_arg;
4234                                 if (IS_STRICT_MODE (ctx)) {
4235                                         MonoType *underlying_type = mono_type_get_underlying_type_any (type);
4236                                         MonoType *underlying_candidate = mono_type_get_underlying_type_any (candidate);
4237                                         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)) ||
4238                                                 (IS_ONE_OF2 (underlying_candidate->type, MONO_TYPE_I4, MONO_TYPE_U4) && IS_ONE_OF2 (underlying_type->type, MONO_TYPE_I, MONO_TYPE_U)))
4239                                                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
4240                                 }
4241                                 if (!verify_type_compatibility_full (ctx, type, candidate, TRUE))
4242                                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
4243                         }
4244                 }
4245         }
4246
4247         set_stack_value (ctx, stack_push (ctx), type, FALSE);
4248 #undef IS_ONE_OF2
4249 }
4250
4251 /*
4252  * FIXME handle arrays that are not 0-indexed
4253  */
4254 static void
4255 do_stelem (VerifyContext *ctx, int opcode, int token)
4256 {
4257         ILStackDesc *index, *array, *value;
4258         MonoType *type;
4259         if (!check_underflow (ctx, 3))
4260                 return;
4261
4262         if (opcode == CEE_STELEM) {
4263                 if (!(type = verifier_load_type (ctx, token, "stelem.any"))) {
4264                         ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
4265                         return;
4266                 }
4267         } else {
4268                 type = mono_type_from_opcode (opcode);
4269         }
4270         
4271         value = stack_pop (ctx);
4272         index = stack_pop (ctx);
4273         array = stack_pop (ctx);
4274
4275         if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4276                 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));
4277
4278         if (!stack_slot_is_null_literal (array)) {
4279                 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY) {
4280                         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));
4281                 } else {
4282                         if (opcode == CEE_STELEM_REF) {
4283                                 if (array->type->data.klass->valuetype)
4284                                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4285                         } else if (!verify_type_compatibility_full (ctx, &array->type->data.klass->byval_arg, type, TRUE)) {
4286                                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4287                         }
4288                 }
4289         }
4290         if (opcode == CEE_STELEM_REF) {
4291                 if (!stack_slot_is_boxed_value (value) && mono_class_from_mono_type (value->type)->valuetype)
4292                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4293         } else if (opcode != CEE_STELEM_REF) {
4294                 if (!verify_stack_type_compatibility (ctx, type, value))
4295                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4296
4297                 if (stack_slot_is_boxed_value (value) && !MONO_TYPE_IS_REFERENCE (value->type) && !MONO_TYPE_IS_REFERENCE (type))
4298                         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));
4299
4300         }
4301 }
4302
4303 static void
4304 do_throw (VerifyContext *ctx)
4305 {
4306         ILStackDesc *exception;
4307         if (!check_underflow (ctx, 1))
4308                 return;
4309         exception = stack_pop (ctx);
4310
4311         if (!stack_slot_is_null_literal (exception) && !(stack_slot_get_type (exception) == TYPE_COMPLEX && !mono_class_from_mono_type (exception->type)->valuetype))
4312                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type on stack for throw, expected reference type at 0x%04x", ctx->ip_offset));
4313
4314         if (mono_type_is_generic_argument (exception->type) && !stack_slot_is_boxed_value (exception)) {
4315                 char *name = mono_type_full_name (exception->type);
4316                 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));
4317                 g_free (name);
4318         }
4319         /*The stack is left empty after a throw*/
4320         ctx->eval.size = 0;
4321 }
4322
4323
4324 static void
4325 do_endfilter (VerifyContext *ctx)
4326 {
4327         MonoExceptionClause *clause;
4328
4329         if (IS_STRICT_MODE (ctx)) {
4330                 if (ctx->eval.size != 1)
4331                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack size must have one item for endfilter at 0x%04x", ctx->ip_offset));
4332
4333                 if (ctx->eval.size >= 1 && stack_slot_get_type (stack_pop (ctx)) != TYPE_I4)
4334                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack item type is not an int32 for endfilter at 0x%04x", ctx->ip_offset));
4335         }
4336
4337         if ((clause = is_correct_endfilter (ctx, ctx->ip_offset))) {
4338                 if (IS_STRICT_MODE (ctx)) {
4339                         if (ctx->ip_offset != clause->handler_offset - 2)
4340                                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));                       
4341                 } else {
4342                         if ((ctx->ip_offset != clause->handler_offset - 2) && !MONO_OFFSET_IN_HANDLER (clause, ctx->ip_offset))
4343                                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
4344                 }
4345         } else {
4346                 if (IS_STRICT_MODE (ctx) && !is_unverifiable_endfilter (ctx, ctx->ip_offset))
4347                         ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4348                 else
4349                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4350         }
4351
4352         ctx->eval.size = 0;
4353 }
4354
4355 static void
4356 do_leave (VerifyContext *ctx, int delta)
4357 {
4358         int target = ((gint32)ctx->ip_offset) + delta;
4359         if (target >= ctx->code_size || target < 0)
4360                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
4361
4362         if (!is_correct_leave (ctx->header, ctx->ip_offset, target))
4363                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ctx->ip_offset));
4364         ctx->eval.size = 0;
4365 }
4366
4367 /* 
4368  * do_static_branch:
4369  * 
4370  * Verify br and br.s opcodes.
4371  */
4372 static void
4373 do_static_branch (VerifyContext *ctx, int delta)
4374 {
4375         int target = ctx->ip_offset + delta;
4376         if (target < 0 || target >= ctx->code_size) {
4377                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("branch target out of code at 0x%04x", ctx->ip_offset));
4378                 return;
4379         }
4380
4381         switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4382         case 1:
4383                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4384                 break;
4385         case 2:
4386                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4387                 break;
4388         }
4389
4390         ctx->target = target;
4391 }
4392
4393 static void
4394 do_switch (VerifyContext *ctx, int count, const unsigned char *data)
4395 {
4396         int i, base = ctx->ip_offset + 5 + count * 4;
4397         ILStackDesc *value;
4398
4399         if (!check_underflow (ctx, 1))
4400                 return;
4401
4402         value = stack_pop (ctx);
4403
4404         if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
4405                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to switch at 0x%04x", ctx->ip_offset));
4406
4407         for (i = 0; i < count; ++i) {
4408                 int target = base + read32 (data + i * 4);
4409
4410                 if (target < 0 || target >= ctx->code_size) {
4411                         ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x out of code at 0x%04x", i, ctx->ip_offset));
4412                         return;
4413                 }
4414
4415                 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4416                 case 1:
4417                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4418                         break;
4419                 case 2:
4420                         ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4421                         return;
4422                 }
4423                 merge_stacks (ctx, &ctx->eval, &ctx->code [target], FALSE, TRUE);
4424         }
4425 }
4426
4427 static void
4428 do_load_function_ptr (VerifyContext *ctx, guint32 token, gboolean virtual)
4429 {
4430         ILStackDesc *top;
4431         MonoMethod *method;
4432
4433         if (virtual && !check_underflow (ctx, 1))
4434                 return;
4435
4436         if (!virtual && !check_overflow (ctx))
4437                 return;
4438
4439         if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
4440                 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn  at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4441                 return;
4442         }
4443
4444         if (!(method = verifier_load_method (ctx, token, virtual ? "ldvirtfrn" : "ldftn")))
4445                 return;
4446
4447         if (mono_method_is_constructor (method))
4448                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldftn with a constructor at 0x%04x", ctx->ip_offset));
4449
4450         if (virtual) {
4451                 ILStackDesc *top = stack_pop (ctx);
4452         
4453                 if (stack_slot_get_type (top) != TYPE_COMPLEX || top->type->type == MONO_TYPE_VALUETYPE)
4454                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to ldvirtftn at 0x%04x", ctx->ip_offset));
4455         
4456                 if (method->flags & METHOD_ATTRIBUTE_STATIC)
4457                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldvirtftn with a constructor at 0x%04x", ctx->ip_offset));
4458
4459                 if (!verify_stack_type_compatibility (ctx, &method->klass->byval_arg, top))
4460                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unexpected object for ldvirtftn at 0x%04x", ctx->ip_offset));
4461         }
4462         
4463         if (!mono_method_can_access_method_full (ctx->method, method, NULL))
4464                 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);
4465
4466         top = stack_push_val(ctx, TYPE_PTR, mono_type_create_fnptr_from_mono_method (ctx, method));
4467         top->method = method;
4468 }
4469
4470 static void
4471 do_sizeof (VerifyContext *ctx, int token)
4472 {
4473         MonoType *type;
4474
4475         if (!IS_TYPE_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
4476                 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid type token %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4477                 return;
4478         }
4479         
4480         if (!(type = verifier_load_type (ctx, token, "sizeof")))
4481                 return;
4482
4483         if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
4484                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type at 0x%04x", ctx->ip_offset));
4485                 return;
4486         }
4487
4488         if (type->type == MONO_TYPE_VOID) {
4489                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type at 0x%04x", ctx->ip_offset));
4490                 return;
4491         }
4492
4493         if (check_overflow (ctx))
4494                 set_stack_value (ctx, stack_push (ctx), &mono_defaults.uint32_class->byval_arg, FALSE);
4495 }
4496
4497 /* Stack top can be of any type, the runtime doesn't care and treat everything as an int. */
4498 static void
4499 do_localloc (VerifyContext *ctx)
4500 {
4501         ILStackDesc *top;
4502         
4503         if (ctx->eval.size != 1) {
4504                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4505                 return;         
4506         }
4507
4508         if (in_any_exception_block (ctx->header, ctx->ip_offset)) {
4509                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4510                 return;
4511         }
4512
4513         /*TODO verify top type*/
4514         top = stack_pop (ctx);
4515
4516         set_stack_value (ctx, stack_push (ctx), &mono_defaults.int_class->byval_arg, FALSE);
4517         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Instruction localloc in never verifiable at 0x%04x", ctx->ip_offset));
4518 }
4519
4520 static void
4521 do_ldstr (VerifyContext *ctx, guint32 token)
4522 {
4523         if (mono_metadata_token_code (token) != MONO_TOKEN_STRING) {
4524                 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string token %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4525                 return;
4526         }
4527
4528         if (!ctx->image->dynamic && mono_metadata_token_index (token) >= ctx->image->heap_us.size) {
4529                 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string index %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4530                 return;
4531         }
4532
4533         if (check_overflow (ctx))
4534                 stack_push_val (ctx, TYPE_COMPLEX,  &mono_defaults.string_class->byval_arg);
4535 }
4536
4537 static void
4538 do_refanyval (VerifyContext *ctx, int token)
4539 {
4540         ILStackDesc *top;
4541         MonoType *type;
4542         if (!check_underflow (ctx, 1))
4543                 return;
4544
4545         if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4546                 return;
4547
4548         top = stack_pop (ctx);
4549
4550         if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4551                 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));
4552
4553         set_stack_value (ctx, stack_push (ctx), type, TRUE);
4554 }
4555
4556 static void
4557 do_refanytype (VerifyContext *ctx)
4558 {
4559         ILStackDesc *top;
4560
4561         if (!check_underflow (ctx, 1))
4562                 return;
4563
4564         top = stack_pop (ctx);
4565
4566         if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4567                 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));
4568
4569         set_stack_value (ctx, stack_push (ctx), &mono_defaults.typehandle_class->byval_arg, FALSE);
4570
4571 }
4572
4573 static void
4574 do_mkrefany (VerifyContext *ctx, int token)
4575 {
4576         ILStackDesc *top;
4577         MonoType *type;
4578         if (!check_underflow (ctx, 1))
4579                 return;
4580
4581         if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4582                 return;
4583
4584         top = stack_pop (ctx);
4585
4586         if (stack_slot_is_managed_mutability_pointer (top))
4587                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with mkrefany at 0x%04x", ctx->ip_offset));
4588
4589         if (!stack_slot_is_managed_pointer (top)) {
4590                 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));
4591         }else {
4592                 MonoType *stack_type = mono_type_get_type_byval (top->type);
4593                 if (MONO_TYPE_IS_REFERENCE (type) && !mono_metadata_type_equal (type, stack_type))
4594                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4595                         
4596                 if (!MONO_TYPE_IS_REFERENCE (type) && !verify_type_compatibility_full (ctx, type, stack_type, TRUE))
4597                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4598         }
4599
4600         set_stack_value (ctx, stack_push (ctx), &mono_defaults.typed_reference_class->byval_arg, FALSE);
4601 }
4602
4603 static void
4604 do_ckfinite (VerifyContext *ctx)
4605 {
4606         ILStackDesc *top;
4607         if (!check_underflow (ctx, 1))
4608                 return;
4609
4610         top = stack_pop (ctx);
4611
4612         if (stack_slot_get_underlying_type (top) != TYPE_R8)
4613                 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)); 
4614         stack_push_stack_val (ctx, top);
4615 }
4616 /*
4617  * merge_stacks:
4618  * Merge the stacks and perform compat checks. The merge check if types of @from are mergeable with type of @to 
4619  * 
4620  * @from holds new values for a given control path
4621  * @to holds the current values of a given control path
4622  * 
4623  * TODO we can eliminate the from argument as all callers pass &ctx->eval
4624  */
4625 static void
4626 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external) 
4627 {
4628         int i, j, k;
4629         stack_init (ctx, to);
4630
4631         if (start) {
4632                 if (to->flags == IL_CODE_FLAG_NOT_PROCESSED) 
4633                         from->size = 0;
4634                 else
4635                         stack_copy (&ctx->eval, to);
4636                 goto end_verify;
4637         } else if (!(to->flags & IL_CODE_STACK_MERGED)) {
4638                 stack_copy (to, &ctx->eval);
4639                 goto end_verify;
4640         }
4641         VERIFIER_DEBUG ( printf ("performing stack merge %d x %d\n", from->size, to->size); );
4642
4643         if (from->size != to->size) {
4644                 VERIFIER_DEBUG ( printf ("different stack sizes %d x %d at 0x%04x\n", from->size, to->size, ctx->ip_offset); );
4645                 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)); 
4646                 goto end_verify;
4647         }
4648
4649         //FIXME we need to preserve CMMP attributes
4650         //FIXME we must take null literals into consideration.
4651         for (i = 0; i < from->size; ++i) {
4652                 ILStackDesc *new_slot = from->stack + i;
4653                 ILStackDesc *old_slot = to->stack + i;
4654                 MonoType *new_type = mono_type_from_stack_slot (new_slot);
4655                 MonoType *old_type = mono_type_from_stack_slot (old_slot);
4656                 MonoClass *old_class = mono_class_from_mono_type (old_type);
4657                 MonoClass *new_class = mono_class_from_mono_type (new_type);
4658                 MonoClass *match_class = NULL;
4659
4660                 // S := T then U = S (new value is compatible with current value, keep current)
4661                 if (verify_stack_type_compatibility (ctx, old_type, new_slot)) {
4662                         copy_stack_value (new_slot, old_slot);
4663                         continue;
4664                 }
4665
4666                 // T := S then U = T (old value is compatible with current value, use new)
4667                 if (verify_stack_type_compatibility (ctx, new_type, old_slot)) {
4668                         copy_stack_value (old_slot, new_slot);
4669                         continue;
4670                 }
4671
4672                 if (mono_type_is_generic_argument (old_type) || mono_type_is_generic_argument (new_type)) {
4673                         char *old_name = stack_slot_full_name (old_slot); 
4674                         char *new_name = stack_slot_full_name (new_slot);
4675                         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));
4676                         g_free (old_name);
4677                         g_free (new_name);
4678                         goto end_verify;                        
4679                 } 
4680
4681                 //both are reference types, use closest common super type
4682                 if (!mono_class_from_mono_type (old_type)->valuetype 
4683                         && !mono_class_from_mono_type (new_type)->valuetype
4684                         && !stack_slot_is_managed_pointer (old_slot)
4685                         && !stack_slot_is_managed_pointer (new_slot)) {
4686                         
4687                         for (j = MIN (old_class->idepth, new_class->idepth) - 1; j > 0; --j) {
4688                                 if (mono_metadata_type_equal (&old_class->supertypes [j]->byval_arg, &new_class->supertypes [j]->byval_arg)) {
4689                                         match_class = old_class->supertypes [j];
4690                                         goto match_found;
4691                                 }
4692                         }
4693
4694                         mono_class_setup_interfaces (old_class);
4695                         for (j = 0; j < old_class->interface_count; ++j) {
4696                                 for (k = 0; k < new_class->interface_count; ++k) {
4697                                         if (mono_metadata_type_equal (&old_class->interfaces [j]->byval_arg, &new_class->interfaces [k]->byval_arg)) {
4698                                                 match_class = old_class->interfaces [j];
4699                                                 goto match_found;
4700                                         }
4701                                 }
4702                         }
4703
4704                         //No decent super type found, use object
4705                         match_class = mono_defaults.object_class;
4706                         goto match_found;
4707                 } 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)) {
4708                         match_class = mono_defaults.object_class;
4709                         goto match_found;
4710                 }
4711
4712                 {
4713                 char *old_name = stack_slot_full_name (old_slot); 
4714                 char *new_name = stack_slot_full_name (new_slot);
4715                 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)); 
4716                 g_free (old_name);
4717                 g_free (new_name);
4718                 }
4719                 set_stack_value (ctx, old_slot, &new_class->byval_arg, stack_slot_is_managed_pointer (old_slot));
4720                 goto end_verify;
4721
4722 match_found:
4723                 g_assert (match_class);
4724                 set_stack_value (ctx, old_slot, &match_class->byval_arg, stack_slot_is_managed_pointer (old_slot));
4725                 set_stack_value (ctx, new_slot, &match_class->byval_arg, stack_slot_is_managed_pointer (old_slot));
4726                 continue;
4727         }
4728
4729 end_verify:
4730         if (external)
4731                 to->flags |= IL_CODE_FLAG_WAS_TARGET;
4732         to->flags |= IL_CODE_STACK_MERGED;
4733 }
4734
4735 #define HANDLER_START(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER ? (clause)->data.filter_offset : clause->handler_offset)
4736 #define IS_CATCH_OR_FILTER(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER || (clause)->flags == MONO_EXCEPTION_CLAUSE_NONE)
4737
4738 /*
4739  * is_clause_in_range :
4740  * 
4741  * Returns TRUE if either the protected block or the handler of @clause is in the @start - @end range.  
4742  */
4743 static gboolean
4744 is_clause_in_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4745 {
4746         if (clause->try_offset >= start && clause->try_offset < end)
4747                 return TRUE;
4748         if (HANDLER_START (clause) >= start && HANDLER_START (clause) < end)
4749                 return TRUE;
4750         return FALSE;
4751 }
4752
4753 /*
4754  * is_clause_inside_range :
4755  * 
4756  * Returns TRUE if @clause lies completely inside the @start - @end range.  
4757  */
4758 static gboolean
4759 is_clause_inside_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4760 {
4761         if (clause->try_offset < start || (clause->try_offset + clause->try_len) > end)
4762                 return FALSE;
4763         if (HANDLER_START (clause) < start || (clause->handler_offset + clause->handler_len) > end)
4764                 return FALSE;
4765         return TRUE;
4766 }
4767
4768 /*
4769  * is_clause_nested :
4770  * 
4771  * Returns TRUE if @nested is nested in @clause.   
4772  */
4773 static gboolean
4774 is_clause_nested (MonoExceptionClause *clause, MonoExceptionClause *nested)
4775 {
4776         if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (nested, clause->data.filter_offset, clause->handler_offset))
4777                 return TRUE;
4778         return is_clause_inside_range (nested, clause->try_offset, clause->try_offset + clause->try_len) ||
4779         is_clause_inside_range (nested, clause->handler_offset, clause->handler_offset + clause->handler_len);
4780 }
4781
4782 /* Test the relationship between 2 exception clauses. Follow  P.1 12.4.2.7 of ECMA
4783  * the each pair of exception must have the following properties:
4784  *  - one is fully nested on another (the outer must not be a filter clause) (the nested one must come earlier)
4785  *  - completely disjoin (none of the 3 regions of each entry overlap with the other 3)
4786  *  - mutual protection (protected block is EXACT the same, handlers are disjoin and all handler are catch or all handler are filter)
4787  */
4788 static void
4789 verify_clause_relationship (VerifyContext *ctx, MonoExceptionClause *clause, MonoExceptionClause *to_test)
4790 {
4791         /*clause is nested*/
4792         if (to_test->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (clause, to_test->data.filter_offset, to_test->handler_offset)) {
4793                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clause inside filter"));
4794                 return;
4795         }
4796
4797         /*wrong nesting order.*/
4798         if (is_clause_nested (clause, to_test)) {
4799                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Nested exception clause appears after enclosing clause"));
4800                 return;
4801         }
4802
4803         /*mutual protection*/
4804         if (clause->try_offset == to_test->try_offset && clause->try_len == to_test->try_len) {
4805                 /*handlers are not disjoint*/
4806                 if (is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) {
4807                         ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception handlers overlap"));
4808                         return;
4809                 }
4810                 /* handlers are not catch or filter */
4811                 if (!IS_CATCH_OR_FILTER (clause) || !IS_CATCH_OR_FILTER (to_test)) {
4812                         ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses with shared protected block are neither catch or filter"));
4813                         return;
4814                 }
4815                 /*OK*/
4816                 return;
4817         }
4818
4819         /*not completelly disjoint*/
4820         if ((is_clause_in_range (to_test, clause->try_offset, clause->try_offset + clause->try_len) ||
4821                 is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) && !is_clause_nested (to_test, clause))
4822                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses overlap"));
4823 }
4824
4825 #define code_bounds_check(size) \
4826         if (ip + size > end) {\
4827                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Code overrun starting with 0x%x at 0x%04x", *ip, ctx.ip_offset)); \
4828                 break; \
4829         } \
4830
4831 /*
4832  * FIXME: need to distinguish between valid and verifiable.
4833  * Need to keep track of types on the stack.
4834  * Verify types for opcodes.
4835  */
4836 GSList*
4837 mono_method_verify (MonoMethod *method, int level)
4838 {
4839         const unsigned char *ip;
4840         const unsigned char *end;
4841         int i, n, need_merge = 0, start = 0;
4842         guint token, ip_offset = 0, prefix = 0;
4843         MonoGenericContext *generic_context = NULL;
4844         MonoImage *image;
4845         VerifyContext ctx;
4846         GSList *tmp;
4847         VERIFIER_DEBUG ( printf ("Verify IL for method %s %s %s\n",  method->klass->name_space,  method->klass->name, method->name); );
4848
4849         if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
4850                         (method->flags & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT))) {
4851                 return NULL;
4852         }
4853
4854         memset (&ctx, 0, sizeof (VerifyContext));
4855
4856         //FIXME use mono_method_get_signature_full
4857         ctx.signature = mono_method_signature (method);
4858         if (!ctx.signature) {
4859                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method signature"));
4860                 return ctx.list;
4861         }
4862         ctx.header = mono_method_get_header (method);
4863         if (!ctx.header) {
4864                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method header"));
4865                 return ctx.list;
4866         }
4867         ctx.method = method;
4868         ip = ctx.header->code;
4869         end = ip + ctx.header->code_size;
4870         ctx.image = image = method->klass->image;
4871
4872
4873         ctx.max_args = ctx.signature->param_count + ctx.signature->hasthis;
4874         ctx.max_stack = ctx.header->max_stack;
4875         ctx.verifiable = ctx.valid = 1;
4876         ctx.level = level;
4877
4878         ctx.code = g_new (ILCodeDesc, ctx.header->code_size);
4879         ctx.code_size = ctx.header->code_size;
4880
4881         memset(ctx.code, 0, sizeof (ILCodeDesc) * ctx.header->code_size);
4882
4883
4884         ctx.num_locals = ctx.header->num_locals;
4885         ctx.locals = g_memdup (ctx.header->locals, sizeof (MonoType*) * ctx.header->num_locals);
4886
4887         if (ctx.num_locals > 0 && !ctx.header->init_locals)
4888                 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Method with locals variable but without init locals set"));
4889
4890         ctx.params = g_new (MonoType*, ctx.max_args);
4891         if (ctx.signature->hasthis)
4892                 ctx.params [0] = method->klass->valuetype ? &method->klass->this_arg : &method->klass->byval_arg;
4893         memcpy (ctx.params + ctx.signature->hasthis, ctx.signature->params, sizeof (MonoType *) * ctx.signature->param_count);
4894
4895         if (ctx.signature->is_inflated)
4896                 ctx.generic_context = generic_context = mono_method_get_context (method);
4897
4898         if (!generic_context && (method->klass->generic_container || method->is_generic)) {
4899                 if (method->is_generic)
4900                         ctx.generic_context = generic_context = &(mono_method_get_generic_container (method)->context);
4901                 else
4902                         ctx.generic_context = generic_context = &method->klass->generic_container->context;
4903         }
4904
4905         for (i = 0; i < ctx.num_locals; ++i)
4906                 ctx.locals [i] = mono_class_inflate_generic_type (ctx.locals [i], ctx.generic_context);
4907         for (i = 0; i < ctx.max_args; ++i)
4908                 ctx.params [i] = mono_class_inflate_generic_type (ctx.params [i], ctx.generic_context);
4909         stack_init (&ctx, &ctx.eval);
4910
4911         for (i = 0; i < ctx.num_locals; ++i) {
4912                 if (!mono_type_is_valid_in_context (&ctx, ctx.locals [i]))
4913                         break;
4914         }
4915
4916         for (i = 0; i < ctx.max_args; ++i) {
4917                 if (!mono_type_is_valid_in_context (&ctx, ctx.params [i]))
4918                         break;
4919         }
4920
4921         if (!ctx.valid)
4922                 goto cleanup;
4923
4924         for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
4925                 MonoExceptionClause *clause = ctx.header->clauses + i;
4926                 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); );
4927
4928                 if (clause->try_offset > ctx.code_size || clause->try_offset + clause->try_len > ctx.code_size)
4929                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause out of bounds at 0x%04x", clause->try_offset));
4930
4931                 if (clause->try_len <= 0)
4932                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause len <= 0 at 0x%04x", clause->try_offset));
4933
4934                 if (clause->handler_offset > ctx.code_size || clause->handler_offset + clause->handler_len > ctx.code_size)
4935                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause out of bounds at 0x%04x", clause->try_offset));
4936
4937                 if (clause->handler_len <= 0)
4938                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause len <= 0 at 0x%04x", clause->try_offset));
4939
4940                 if (clause->try_offset < clause->handler_offset && clause->try_offset + clause->try_len > HANDLER_START (clause))
4941                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try block (at 0x%04x) includes handler block (at 0x%04x)", clause->try_offset, clause->handler_offset));
4942
4943                 for (n = i + 1; n < ctx.header->num_clauses && ctx.valid; ++n)
4944                         verify_clause_relationship (&ctx, clause, ctx.header->clauses + n);
4945
4946                 if (!ctx.valid)
4947                         break;
4948
4949                 ctx.code [clause->try_offset].flags |= IL_CODE_FLAG_WAS_TARGET;
4950                 if (clause->try_offset + clause->try_len < ctx.code_size)
4951                         ctx.code [clause->try_offset + clause->try_len].flags |= IL_CODE_FLAG_WAS_TARGET;
4952                 if (clause->handler_offset + clause->handler_len < ctx.code_size)
4953                         ctx.code [clause->handler_offset + clause->handler_len].flags |= IL_CODE_FLAG_WAS_TARGET;
4954
4955                 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
4956                         init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, clause->data.catch_class);
4957                 }
4958                 else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4959                         init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->data.filter_offset, mono_defaults.exception_class);
4960                         init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, mono_defaults.exception_class);   
4961                 }
4962         }
4963
4964         while (ip < end && ctx.valid) {
4965                 ctx.ip_offset = ip_offset = ip - ctx.header->code;
4966
4967                 /*We need to check against fallthrou in and out of protected blocks.
4968                  * For fallout we check the once a protected block ends, if the start flag is not set.
4969                  * Likewise for fallthru in, we check if ip is the start of a protected block and start is not set
4970                  * TODO convert these checks to be done using flags and not this loop
4971                  */
4972                 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
4973                         MonoExceptionClause *clause = ctx.header->clauses + i;
4974
4975                         if ((clause->try_offset + clause->try_len == ip_offset) && start == 0) {
4976                                 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru off try block at 0x%04x", ip_offset));
4977                                 start = 1;
4978                         }
4979
4980                         if ((clause->handler_offset + clause->handler_len == ip_offset) && start == 0) {
4981                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
4982                                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
4983                                 else
4984                                         CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
4985                                 start = 1;
4986                         }
4987
4988                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && clause->handler_offset == ip_offset && start == 0) {
4989                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of filter block at 0x%04x", ip_offset));
4990                                 start = 1;
4991                         }
4992
4993                         if (clause->handler_offset == ip_offset && start == 0) {
4994                                 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru handler block at 0x%04x", ip_offset));
4995                                 start = 1;
4996                         }
4997
4998                         if (clause->try_offset == ip_offset && ctx.eval.size > 0 && start == 0) {
4999                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Try to enter try block with a non-empty stack at 0x%04x", ip_offset));
5000                                 start = 1;
5001                         }
5002                 }
5003
5004                 if (!ctx.valid)
5005                         break;
5006
5007                 if (need_merge) {
5008                         VERIFIER_DEBUG ( printf ("extra merge needed! 0x%04x \n", ctx.target); );
5009                         merge_stacks (&ctx, &ctx.eval, &ctx.code [ctx.target], FALSE, TRUE);
5010                         need_merge = 0; 
5011                 }
5012                 merge_stacks (&ctx, &ctx.eval, &ctx.code[ip_offset], start, FALSE);
5013                 start = 0;
5014
5015                 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
5016 #ifdef MONO_VERIFIER_DEBUG
5017                 {
5018                         char *discode;
5019                         discode = mono_disasm_code_one (NULL, method, ip, NULL);
5020                         discode [strlen (discode) - 1] = 0; /* no \n */
5021                         g_print ("[%d] %-29s (%d)\n",  ip_offset, discode, ctx.eval.size);
5022                         g_free (discode);
5023                 }
5024                 dump_stack_state (&ctx.code [ip_offset]);
5025                 dump_stack_state (&ctx.eval);
5026 #endif
5027
5028                 switch (*ip) {
5029                 case CEE_NOP:
5030                 case CEE_BREAK:
5031                         ++ip;
5032                         break;
5033
5034                 case CEE_LDARG_0:
5035                 case CEE_LDARG_1:
5036                 case CEE_LDARG_2:
5037                 case CEE_LDARG_3:
5038                         push_arg (&ctx, *ip - CEE_LDARG_0, FALSE);
5039                         ++ip;
5040                         break;
5041
5042                 case CEE_LDARG_S:
5043                 case CEE_LDARGA_S:
5044                         code_bounds_check (2);
5045                         push_arg (&ctx, ip [1],  *ip == CEE_LDARGA_S);
5046                         ip += 2;
5047                         break;
5048
5049                 case CEE_ADD_OVF_UN:
5050                         do_binop (&ctx, *ip, add_ovf_un_table);
5051                         ++ip;
5052                         break;
5053
5054                 case CEE_SUB_OVF_UN:
5055                         do_binop (&ctx, *ip, sub_ovf_un_table);
5056                         ++ip;
5057                         break;
5058
5059                 case CEE_ADD_OVF:
5060                 case CEE_SUB_OVF:
5061                 case CEE_MUL_OVF:
5062                 case CEE_MUL_OVF_UN:
5063                         do_binop (&ctx, *ip, bin_ovf_table);
5064                         ++ip;
5065                         break;
5066
5067                 case CEE_ADD:
5068                         do_binop (&ctx, *ip, add_table);
5069                         ++ip;
5070                         break;
5071
5072                 case CEE_SUB:
5073                         do_binop (&ctx, *ip, sub_table);
5074                         ++ip;
5075                         break;
5076
5077                 case CEE_MUL:
5078                 case CEE_DIV:
5079                 case CEE_REM:
5080                         do_binop (&ctx, *ip, bin_op_table);
5081                         ++ip;
5082                         break;
5083
5084                 case CEE_AND:
5085                 case CEE_DIV_UN:
5086                 case CEE_OR:
5087                 case CEE_REM_UN:
5088                 case CEE_XOR:
5089                         do_binop (&ctx, *ip, int_bin_op_table);
5090                         ++ip;
5091                         break;
5092
5093                 case CEE_SHL:
5094                 case CEE_SHR:
5095                 case CEE_SHR_UN:
5096                         do_binop (&ctx, *ip, shift_op_table);
5097                         ++ip;
5098                         break;
5099
5100                 case CEE_POP:
5101                         if (!check_underflow (&ctx, 1))
5102                                 break;
5103                         stack_pop_safe (&ctx);
5104                         ++ip;
5105                         break;
5106
5107                 case CEE_RET:
5108                         do_ret (&ctx);
5109                         ++ip;
5110                         start = 1;
5111                         break;
5112
5113                 case CEE_LDLOC_0:
5114                 case CEE_LDLOC_1:
5115                 case CEE_LDLOC_2:
5116                 case CEE_LDLOC_3:
5117                         /*TODO support definite assignment verification? */
5118                         push_local (&ctx, *ip - CEE_LDLOC_0, FALSE);
5119                         ++ip;
5120                         break;
5121
5122                 case CEE_STLOC_0:
5123                 case CEE_STLOC_1:
5124                 case CEE_STLOC_2:
5125                 case CEE_STLOC_3:
5126                         store_local (&ctx, *ip - CEE_STLOC_0);
5127                         ++ip;
5128                         break;
5129
5130                 case CEE_STLOC_S:
5131                         code_bounds_check (2);
5132                         store_local (&ctx, ip [1]);
5133                         ip += 2;
5134                         break;
5135
5136                 case CEE_STARG_S:
5137                         code_bounds_check (2);
5138                         store_arg (&ctx, ip [1]);
5139                         ip += 2;
5140                         break;
5141
5142                 case CEE_LDC_I4_M1:
5143                 case CEE_LDC_I4_0:
5144                 case CEE_LDC_I4_1:
5145                 case CEE_LDC_I4_2:
5146                 case CEE_LDC_I4_3:
5147                 case CEE_LDC_I4_4:
5148                 case CEE_LDC_I4_5:
5149                 case CEE_LDC_I4_6:
5150                 case CEE_LDC_I4_7:
5151                 case CEE_LDC_I4_8:
5152                         if (check_overflow (&ctx))
5153                                 stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
5154                         ++ip;
5155                         break;
5156
5157                 case CEE_LDC_I4_S:
5158                         code_bounds_check (2);
5159                         if (check_overflow (&ctx))
5160                                 stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
5161                         ip += 2;
5162                         break;
5163
5164                 case CEE_LDC_I4:
5165                         code_bounds_check (5);
5166                         if (check_overflow (&ctx))
5167                                 stack_push_val (&ctx,TYPE_I4, &mono_defaults.int32_class->byval_arg);
5168                         ip += 5;
5169                         break;
5170
5171                 case CEE_LDC_I8:
5172                         code_bounds_check (9);
5173                         if (check_overflow (&ctx))
5174                                 stack_push_val (&ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
5175                         ip += 9;
5176                         break;
5177
5178                 case CEE_LDC_R4:
5179                         code_bounds_check (5);
5180                         if (check_overflow (&ctx))
5181                                 stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
5182                         ip += 5;
5183                         break;
5184
5185                 case CEE_LDC_R8:
5186                         code_bounds_check (9);
5187                         if (check_overflow (&ctx))
5188                                 stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
5189                         ip += 9;
5190                         break;
5191
5192                 case CEE_LDNULL:
5193                         if (check_overflow (&ctx))
5194                                 stack_push_val (&ctx, TYPE_COMPLEX | NULL_LITERAL_MASK, &mono_defaults.object_class->byval_arg);
5195                         ++ip;
5196                         break;
5197
5198                 case CEE_BEQ_S:
5199                 case CEE_BNE_UN_S:
5200                         code_bounds_check (2);
5201                         do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_eq_op);
5202                         ip += 2;
5203                         need_merge = 1;
5204                         break;
5205
5206                 case CEE_BGE_S:
5207                 case CEE_BGT_S:
5208                 case CEE_BLE_S:
5209                 case CEE_BLT_S:
5210                 case CEE_BGE_UN_S:
5211                 case CEE_BGT_UN_S:
5212                 case CEE_BLE_UN_S:
5213                 case CEE_BLT_UN_S:
5214                         code_bounds_check (2);
5215                         do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_op);
5216                         ip += 2;
5217                         need_merge = 1;
5218                         break;
5219
5220                 case CEE_BEQ:
5221                 case CEE_BNE_UN:
5222                         code_bounds_check (5);
5223                         do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_eq_op);
5224                         ip += 5;
5225                         need_merge = 1;
5226                         break;
5227
5228                 case CEE_BGE:
5229                 case CEE_BGT:
5230                 case CEE_BLE:
5231                 case CEE_BLT:
5232                 case CEE_BGE_UN:
5233                 case CEE_BGT_UN:
5234                 case CEE_BLE_UN:
5235                 case CEE_BLT_UN:
5236                         code_bounds_check (5);
5237                         do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_op);
5238                         ip += 5;
5239                         need_merge = 1;
5240                         break;
5241
5242                 case CEE_LDLOC_S:
5243                 case CEE_LDLOCA_S:
5244                         code_bounds_check (2);
5245                         push_local (&ctx, ip[1], *ip == CEE_LDLOCA_S);
5246                         ip += 2;
5247                         break;
5248
5249                 /* FIXME: warn/error instead? */
5250                 case CEE_UNUSED99:
5251                         ++ip;
5252                         break; 
5253
5254                 case CEE_DUP: {
5255                         ILStackDesc * top;
5256                         if (!check_underflow (&ctx, 1))
5257                                 break;
5258                         if (!check_overflow (&ctx))
5259                                 break;
5260                         top = stack_pop_safe (&ctx);
5261                         copy_stack_value (stack_push (&ctx), top); 
5262                         copy_stack_value (stack_push (&ctx), top);
5263                         ++ip;
5264                         break;
5265                 }
5266
5267                 case CEE_JMP:
5268                         code_bounds_check (5);
5269                         if (ctx.eval.size)
5270                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Eval stack must be empty in jmp at 0x%04x", ip_offset));
5271                         token = read32 (ip + 1);
5272                         if (in_any_block (ctx.header, ip_offset))
5273                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("jmp cannot escape exception blocks at 0x%04x", ip_offset));
5274
5275                         CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction jmp is not verifiable at 0x%04x", ctx.ip_offset));
5276                         /*
5277                          * FIXME: check signature, retval, arguments etc.
5278                          */
5279                         ip += 5;
5280                         break;
5281                 case CEE_CALL:
5282                 case CEE_CALLVIRT:
5283                         code_bounds_check (5);
5284                         do_invoke_method (&ctx, read32 (ip + 1), *ip == CEE_CALLVIRT);
5285                         ip += 5;
5286                         break;
5287
5288                 case CEE_CALLI:
5289                         code_bounds_check (5);
5290                         token = read32 (ip + 1);
5291                         /*
5292                          * FIXME: check signature, retval, arguments etc.
5293                          * FIXME: check requirements for tail call
5294                          */
5295                         CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction calli is not verifiable at 0x%04x", ctx.ip_offset));
5296                         ip += 5;
5297                         break;
5298                 case CEE_BR_S:
5299                         code_bounds_check (2);
5300                         do_static_branch (&ctx, (signed char)ip [1] + 2);
5301                         need_merge = 1;
5302                         ip += 2;
5303                         start = 1;
5304                         break;
5305
5306                 case CEE_BRFALSE_S:
5307                 case CEE_BRTRUE_S:
5308                         code_bounds_check (2);
5309                         do_boolean_branch_op (&ctx, (signed char)ip [1] + 2);
5310                         ip += 2;
5311                         need_merge = 1;
5312                         break;
5313
5314                 case CEE_BR:
5315                         code_bounds_check (5);
5316                         do_static_branch (&ctx, (gint32)read32 (ip + 1) + 5);
5317                         need_merge = 1;
5318                         ip += 5;
5319                         start = 1;
5320                         break;
5321
5322                 case CEE_BRFALSE:
5323                 case CEE_BRTRUE:
5324                         code_bounds_check (5);
5325                         do_boolean_branch_op (&ctx, (gint32)read32 (ip + 1) + 5);
5326                         ip += 5;
5327                         need_merge = 1;
5328                         break;
5329
5330                 case CEE_SWITCH:
5331                         code_bounds_check (5);
5332                         n = read32 (ip + 1);
5333                         code_bounds_check (5 + sizeof (guint32) * n);
5334                         
5335                         do_switch (&ctx, n, (ip + 5));
5336                         start = 1;
5337                         ip += 5 + sizeof (guint32) * n;
5338                         break;
5339
5340                 case CEE_LDIND_I1:
5341                 case CEE_LDIND_U1:
5342                 case CEE_LDIND_I2:
5343                 case CEE_LDIND_U2:
5344                 case CEE_LDIND_I4:
5345                 case CEE_LDIND_U4:
5346                 case CEE_LDIND_I8:
5347                 case CEE_LDIND_I:
5348                 case CEE_LDIND_R4:
5349                 case CEE_LDIND_R8:
5350                 case CEE_LDIND_REF:
5351                         do_load_indirect (&ctx, *ip);
5352                         ++ip;
5353                         break;
5354                         
5355                 case CEE_STIND_REF:
5356                 case CEE_STIND_I1:
5357                 case CEE_STIND_I2:
5358                 case CEE_STIND_I4:
5359                 case CEE_STIND_I8:
5360                 case CEE_STIND_R4:
5361                 case CEE_STIND_R8:
5362                 case CEE_STIND_I:
5363                         do_store_indirect (&ctx, *ip);
5364                         ++ip;
5365                         break;
5366
5367                 case CEE_NOT:
5368                 case CEE_NEG:
5369                         do_unary_math_op (&ctx, *ip);
5370                         ++ip;
5371                         break;
5372
5373                 case CEE_CONV_I1:
5374                 case CEE_CONV_I2:
5375                 case CEE_CONV_I4:
5376                 case CEE_CONV_U1:
5377                 case CEE_CONV_U2:
5378                 case CEE_CONV_U4:
5379                         do_conversion (&ctx, TYPE_I4);
5380                         ++ip;
5381                         break;                  
5382
5383                 case CEE_CONV_I8:
5384                 case CEE_CONV_U8:
5385                         do_conversion (&ctx, TYPE_I8);
5386                         ++ip;
5387                         break;                  
5388
5389                 case CEE_CONV_R4:
5390                 case CEE_CONV_R8:
5391                 case CEE_CONV_R_UN:
5392                         do_conversion (&ctx, TYPE_R8);
5393                         ++ip;
5394                         break;                  
5395
5396                 case CEE_CONV_I:
5397                 case CEE_CONV_U:
5398                         do_conversion (&ctx, TYPE_NATIVE_INT);
5399                         ++ip;
5400                         break;
5401
5402                 case CEE_CPOBJ:
5403                         code_bounds_check (5);
5404                         do_cpobj (&ctx, read32 (ip + 1));
5405                         ip += 5;
5406                         break;
5407
5408                 case CEE_LDOBJ:
5409                         code_bounds_check (5);
5410                         do_ldobj_value (&ctx, read32 (ip + 1));
5411                         ip += 5;
5412                         break;
5413
5414                 case CEE_LDSTR:
5415                         code_bounds_check (5);
5416                         do_ldstr (&ctx, read32 (ip + 1));
5417                         ip += 5;
5418                         break;
5419
5420                 case CEE_NEWOBJ:
5421                         code_bounds_check (5);
5422                         do_newobj (&ctx, read32 (ip + 1));
5423                         ip += 5;
5424                         break;
5425
5426                 case CEE_CASTCLASS:
5427                 case CEE_ISINST:
5428                         code_bounds_check (5);
5429                         do_cast (&ctx, read32 (ip + 1), *ip == CEE_CASTCLASS ? "castclass" : "isinst");
5430                         ip += 5;
5431                         break;
5432
5433                 case CEE_UNUSED58:
5434                 case CEE_UNUSED1:
5435                         ++ip; /* warn, error ? */
5436                         break;
5437
5438                 case CEE_UNBOX:
5439                         code_bounds_check (5);
5440                         do_unbox_value (&ctx, read32 (ip + 1));
5441                         ip += 5;
5442                         break;
5443
5444                 case CEE_THROW:
5445                         do_throw (&ctx);
5446                         start = 1;
5447                         ++ip;
5448                         break;
5449
5450                 case CEE_LDFLD:
5451                 case CEE_LDFLDA:
5452                         code_bounds_check (5);
5453                         do_push_field (&ctx, read32 (ip + 1), *ip == CEE_LDFLDA);
5454                         ip += 5;
5455                         break;
5456
5457                 case CEE_LDSFLD:
5458                 case CEE_LDSFLDA:
5459                         code_bounds_check (5);
5460                         do_push_static_field (&ctx, read32 (ip + 1), *ip == CEE_LDSFLDA);
5461                         ip += 5;
5462                         break;
5463
5464                 case CEE_STFLD:
5465                         code_bounds_check (5);
5466                         do_store_field (&ctx, read32 (ip + 1));
5467                         ip += 5;
5468                         break;
5469
5470                 case CEE_STSFLD:
5471                         code_bounds_check (5);
5472                         do_store_static_field (&ctx, read32 (ip + 1));
5473                         ip += 5;
5474                         break;
5475
5476                 case CEE_STOBJ:
5477                         code_bounds_check (5);
5478                         do_stobj (&ctx, read32 (ip + 1));
5479                         ip += 5;
5480                         break;
5481
5482                 case CEE_CONV_OVF_I1_UN:
5483                 case CEE_CONV_OVF_I2_UN:
5484                 case CEE_CONV_OVF_I4_UN:
5485                 case CEE_CONV_OVF_U1_UN:
5486                 case CEE_CONV_OVF_U2_UN:
5487                 case CEE_CONV_OVF_U4_UN:
5488                         do_conversion (&ctx, TYPE_I4);
5489                         ++ip;
5490                         break;                  
5491
5492                 case CEE_CONV_OVF_I8_UN:
5493                 case CEE_CONV_OVF_U8_UN:
5494                         do_conversion (&ctx, TYPE_I8);
5495                         ++ip;
5496                         break;                  
5497
5498                 case CEE_CONV_OVF_I_UN:
5499                 case CEE_CONV_OVF_U_UN:
5500                         do_conversion (&ctx, TYPE_NATIVE_INT);
5501                         ++ip;
5502                         break;
5503
5504                 case CEE_BOX:
5505                         code_bounds_check (5);
5506                         do_box_value (&ctx, read32 (ip + 1));
5507                         ip += 5;
5508                         break;
5509
5510                 case CEE_NEWARR:
5511                         code_bounds_check (5);
5512                         do_newarr (&ctx, read32 (ip + 1));
5513                         ip += 5;
5514                         break;
5515
5516                 case CEE_LDLEN:
5517                         do_ldlen (&ctx);
5518                         ++ip;
5519                         break;
5520
5521                 case CEE_LDELEMA:
5522                         code_bounds_check (5);
5523                         do_ldelema (&ctx, read32 (ip + 1));
5524                         ip += 5;
5525                         break;
5526
5527                 case CEE_LDELEM_I1:
5528                 case CEE_LDELEM_U1:
5529                 case CEE_LDELEM_I2:
5530                 case CEE_LDELEM_U2:
5531                 case CEE_LDELEM_I4:
5532                 case CEE_LDELEM_U4:
5533                 case CEE_LDELEM_I8:
5534                 case CEE_LDELEM_I:
5535                 case CEE_LDELEM_R4:
5536                 case CEE_LDELEM_R8:
5537                 case CEE_LDELEM_REF:
5538                         do_ldelem (&ctx, *ip, 0);
5539                         ++ip;
5540                         break;
5541
5542                 case CEE_STELEM_I:
5543                 case CEE_STELEM_I1:
5544                 case CEE_STELEM_I2:
5545                 case CEE_STELEM_I4:
5546                 case CEE_STELEM_I8:
5547                 case CEE_STELEM_R4:
5548                 case CEE_STELEM_R8:
5549                 case CEE_STELEM_REF:
5550                         do_stelem (&ctx, *ip, 0);
5551                         ++ip;
5552                         break;
5553
5554                 case CEE_LDELEM:
5555                         code_bounds_check (5);
5556                         do_ldelem (&ctx, *ip, read32 (ip + 1));
5557                         ip += 5;
5558                         break;
5559
5560                 case CEE_STELEM:
5561                         code_bounds_check (5);
5562                         do_stelem (&ctx, *ip, read32 (ip + 1));
5563                         ip += 5;
5564                         break;
5565                         
5566                 case CEE_UNBOX_ANY:
5567                         code_bounds_check (5);
5568                         do_unbox_any (&ctx, read32 (ip + 1));
5569                         ip += 5;
5570                         break;
5571
5572                 case CEE_CONV_OVF_I1:
5573                 case CEE_CONV_OVF_U1:
5574                 case CEE_CONV_OVF_I2:
5575                 case CEE_CONV_OVF_U2:
5576                 case CEE_CONV_OVF_I4:
5577                 case CEE_CONV_OVF_U4:
5578                         do_conversion (&ctx, TYPE_I4);
5579                         ++ip;
5580                         break;
5581
5582                 case CEE_CONV_OVF_I8:
5583                 case CEE_CONV_OVF_U8:
5584                         do_conversion (&ctx, TYPE_I8);
5585                         ++ip;
5586                         break;
5587
5588                 case CEE_CONV_OVF_I:
5589                 case CEE_CONV_OVF_U:
5590                         do_conversion (&ctx, TYPE_NATIVE_INT);
5591                         ++ip;
5592                         break;
5593
5594                 case CEE_REFANYVAL:
5595                         code_bounds_check (5);
5596                         do_refanyval (&ctx, read32 (ip + 1));
5597                         ip += 5;
5598                         break;
5599
5600                 case CEE_CKFINITE:
5601                         do_ckfinite (&ctx);
5602                         ++ip;
5603                         break;
5604
5605                 case CEE_MKREFANY:
5606                         code_bounds_check (5);
5607                         do_mkrefany (&ctx,  read32 (ip + 1));
5608                         ip += 5;
5609                         break;
5610
5611                 case CEE_LDTOKEN:
5612                         code_bounds_check (5);
5613                         do_load_token (&ctx, read32 (ip + 1));
5614                         ip += 5;
5615                         break;
5616
5617                 case CEE_ENDFINALLY:
5618                         if (!is_correct_endfinally (ctx.header, ip_offset))
5619                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("endfinally must be used inside a finally/fault handler at 0x%04x", ctx.ip_offset));
5620                         ctx.eval.size = 0;
5621                         start = 1;
5622                         ++ip;
5623                         break;
5624
5625                 case CEE_LEAVE:
5626                         code_bounds_check (5);
5627                         do_leave (&ctx, read32 (ip + 1) + 5);
5628                         ip += 5;
5629                         start = 1;
5630                         break;
5631
5632                 case CEE_LEAVE_S:
5633                         code_bounds_check (2);
5634                         do_leave (&ctx, (signed char)ip [1] + 2);
5635                         ip += 2;
5636                         start = 1;
5637                         break;
5638
5639                 case CEE_PREFIX1:
5640                         code_bounds_check (2);
5641                         ++ip;
5642                         switch (*ip) {
5643                         case CEE_STLOC:
5644                                 code_bounds_check (3);
5645                                 store_local (&ctx, read16 (ip + 1));
5646                                 ip += 3;
5647                                 break;
5648
5649                         case CEE_CEQ:
5650                                 do_cmp_op (&ctx, cmp_br_eq_op, *ip);
5651                                 ++ip;
5652                                 break;
5653
5654                         case CEE_CGT:
5655                         case CEE_CGT_UN:
5656                         case CEE_CLT:
5657                         case CEE_CLT_UN:
5658                                 do_cmp_op (&ctx, cmp_br_op, *ip);
5659                                 ++ip;
5660                                 break;
5661
5662                         case CEE_STARG:
5663                                 code_bounds_check (3);
5664                                 store_arg (&ctx, read16 (ip + 1) );
5665                                 ip += 3;
5666                                 break;
5667
5668
5669                         case CEE_ARGLIST:
5670                                 check_overflow (&ctx);
5671                                 if (ctx.signature->call_convention != MONO_CALL_VARARG)
5672                                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot use arglist on method without VARGARG calling convention at 0x%04x", ctx.ip_offset));
5673                                 set_stack_value (&ctx, stack_push (&ctx), &mono_defaults.argumenthandle_class->byval_arg, FALSE);
5674                                 ++ip;
5675                                 break;
5676         
5677                         case CEE_LDFTN:
5678                                 code_bounds_check (5);
5679                                 do_load_function_ptr (&ctx, read32 (ip + 1), FALSE);
5680                                 ip += 5;
5681                                 break;
5682
5683                         case CEE_LDVIRTFTN:
5684                                 code_bounds_check (5);
5685                                 do_load_function_ptr (&ctx, read32 (ip + 1), TRUE);
5686                                 ip += 5;
5687                                 break;
5688
5689                         case CEE_UNUSED56:
5690                                 ++ip;
5691                                 break;
5692
5693                         case CEE_LDARG:
5694                         case CEE_LDARGA:
5695                                 code_bounds_check (3);
5696                                 push_arg (&ctx, read16 (ip + 1),  *ip == CEE_LDARGA);
5697                                 ip += 3;
5698                                 break;
5699
5700                         case CEE_LDLOC:
5701                         case CEE_LDLOCA:
5702                                 code_bounds_check (3);
5703                                 push_local (&ctx, read16 (ip + 1), *ip == CEE_LDLOCA);
5704                                 ip += 3;
5705                                 break;
5706
5707                         case CEE_LOCALLOC:
5708                                 do_localloc (&ctx);
5709                                 ++ip;
5710                                 break;
5711
5712                         case CEE_UNUSED57:
5713                                 ++ip;
5714                                 break;
5715                         case CEE_ENDFILTER:
5716                                 do_endfilter (&ctx);
5717                                 start = 1;
5718                                 ++ip;
5719                                 break;
5720                         case CEE_UNALIGNED_:
5721                                 code_bounds_check (2);
5722                                 prefix |= PREFIX_UNALIGNED;
5723                                 ip += 2;
5724                                 break;
5725                         case CEE_VOLATILE_:
5726                                 prefix |= PREFIX_VOLATILE;
5727                                 ++ip;
5728                                 break;
5729                         case CEE_TAIL_:
5730                                 prefix |= PREFIX_TAIL;
5731                                 ++ip;
5732                                 if (ip < end && (*ip != CEE_CALL && *ip != CEE_CALLI && *ip != CEE_CALLVIRT))
5733                                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("tail prefix must be used only with call opcodes at 0x%04x", ip_offset));
5734                                 break;
5735
5736                         case CEE_INITOBJ:
5737                                 code_bounds_check (5);
5738                                 do_initobj (&ctx, read32 (ip + 1));
5739                                 ip += 5;
5740                                 break;
5741
5742                         case CEE_CONSTRAINED_:
5743                                 code_bounds_check (5);
5744                                 ctx.constrained_type = get_boxable_mono_type (&ctx, read32 (ip + 1), "constrained.");
5745                                 prefix |= PREFIX_CONSTRAINED;
5746                                 ip += 5;
5747                                 break;
5748         
5749                         case CEE_READONLY_:
5750                                 prefix |= PREFIX_READONLY;
5751                                 ip++;
5752                                 break;
5753
5754                         case CEE_CPBLK:
5755                                 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5756                                 if (!check_underflow (&ctx, 3))
5757                                         break;
5758                                 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction cpblk is not verifiable at 0x%04x", ctx.ip_offset));
5759                                 ip++;
5760                                 break;
5761                                 
5762                         case CEE_INITBLK:
5763                                 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5764                                 if (!check_underflow (&ctx, 3))
5765                                         break;
5766                                 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction initblk is not verifiable at 0x%04x", ctx.ip_offset));
5767                                 ip++;
5768                                 break;
5769                                 
5770                         case CEE_NO_:
5771                                 ip += 2;
5772                                 break;
5773                         case CEE_RETHROW:
5774                                 if (!is_correct_rethrow (ctx.header, ip_offset))
5775                                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("rethrow must be used inside a catch handler at 0x%04x", ctx.ip_offset));
5776                                 ctx.eval.size = 0;
5777                                 start = 1;
5778                                 ++ip;
5779                                 break;
5780                         case CEE_UNUSED:
5781                                 ++ip;
5782                                 break;
5783
5784                         case CEE_SIZEOF:
5785                                 code_bounds_check (5);
5786                                 do_sizeof (&ctx, read32 (ip + 1));
5787                                 ip += 5;
5788                                 break;
5789
5790                         case CEE_REFANYTYPE:
5791                                 do_refanytype (&ctx);
5792                                 ++ip;
5793                                 break;
5794
5795                         default:
5796                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction FE %x at 0x%04x", *ip, ctx.ip_offset));
5797                                 ++ip;
5798                         }
5799                         break;
5800
5801                 default:
5802                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ctx.ip_offset));
5803                         ++ip;
5804                 }
5805
5806                 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
5807                 if (prefix) {
5808                         if (!ctx.prefix_set) //first prefix
5809                                 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
5810                         ctx.prefix_set |= prefix;
5811                         ctx.has_flags = TRUE;
5812                         prefix = 0;
5813                 } else {
5814                         if (!ctx.has_flags)
5815                                 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
5816
5817                         if (ctx.prefix_set & PREFIX_CONSTRAINED)
5818                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after constrained prefix at 0x%04x", ctx.ip_offset));
5819                         if (ctx.prefix_set & PREFIX_READONLY)
5820                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after readonly prefix at 0x%04x", ctx.ip_offset));
5821                         if (ctx.prefix_set & PREFIX_VOLATILE)
5822                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after volatile prefix at 0x%04x", ctx.ip_offset));
5823                         if (ctx.prefix_set & PREFIX_UNALIGNED)
5824                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after unaligned prefix at 0x%04x", ctx.ip_offset));
5825                         ctx.prefix_set = prefix = 0;
5826                         ctx.has_flags = FALSE;
5827                 }
5828         }
5829         /*
5830          * if ip != end we overflowed: mark as error.
5831          */
5832         if ((ip != end || !start) && ctx.verifiable && !ctx.list) {
5833                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Run ahead of method code at 0x%04x", ip_offset));
5834         }
5835
5836         /*We should guard against the last decoded opcode, otherwise we might add errors that doesn't make sense.*/
5837         for (i = 0; i < ctx.code_size && i < ip_offset; ++i) {
5838                 if (ctx.code [i].flags & IL_CODE_FLAG_WAS_TARGET) {
5839                         if (!(ctx.code [i].flags & IL_CODE_FLAG_SEEN))
5840                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or exception block target middle of intruction at 0x%04x", i));
5841
5842                         if (ctx.code [i].flags & IL_CODE_DELEGATE_SEQUENCE)
5843                                 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Branch to delegate code sequence at 0x%04x", i));
5844                 }
5845                 if ((ctx.code [i].flags & IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL) && ctx.has_this_store)
5846                         CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at  0x%04x", i));
5847
5848                 if ((ctx.code [i].flags & IL_CODE_CALL_NONFINAL_VIRTUAL) && ctx.has_this_store)
5849                         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));
5850         }
5851
5852         if (mono_method_is_constructor (ctx.method) && !ctx.super_ctor_called && !ctx.method->klass->valuetype && ctx.method->klass != mono_defaults.object_class)
5853                 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Constructor not calling super\n"));
5854
5855 cleanup:
5856         if (ctx.code) {
5857                 for (i = 0; i < ctx.header->code_size; ++i) {
5858                         if (ctx.code [i].stack)
5859                                 g_free (ctx.code [i].stack);
5860                 }
5861         }
5862
5863         for (tmp = ctx.funptrs; tmp; tmp = tmp->next)
5864                 g_free (tmp->data);
5865         g_slist_free (ctx.funptrs);
5866
5867         for (tmp = ctx.exception_types; tmp; tmp = tmp->next)
5868                 mono_metadata_free_type (tmp->data);
5869         g_slist_free (ctx.exception_types);
5870
5871         for (i = 0; i < ctx.num_locals; ++i)
5872                 mono_metadata_free_type (ctx.locals [i]);
5873         for (i = 0; i < ctx.max_args; ++i)
5874                 mono_metadata_free_type (ctx.params [i]);
5875
5876         if (ctx.eval.stack)
5877                 g_free (ctx.eval.stack);
5878         if (ctx.code)
5879                 g_free (ctx.code);
5880         g_free (ctx.locals);
5881         g_free (ctx.params);
5882
5883         return ctx.list;
5884 }
5885
5886 char*
5887 mono_verify_corlib ()
5888 {
5889         /* This is a public API function so cannot be removed */
5890         return NULL;
5891 }
5892
5893 /*
5894  * Returns true if @method needs to be verified.
5895  * 
5896  */
5897 gboolean
5898 mono_verifier_is_enabled_for_method (MonoMethod *method)
5899 {
5900         return mono_verifier_is_enabled_for_class (method->klass) && method->wrapper_type == MONO_WRAPPER_NONE;
5901 }
5902
5903 /*
5904  * Returns true if @klass need to be verified.
5905  * 
5906  */
5907 gboolean
5908 mono_verifier_is_enabled_for_class (MonoClass *klass)
5909 {
5910         return verify_all || (verifier_mode > MONO_VERIFIER_MODE_OFF && !klass->image->assembly->in_gac && klass->image != mono_defaults.corlib);
5911 }
5912
5913 gboolean
5914 mono_verifier_is_enabled_for_image (MonoImage *image)
5915 {
5916         return verify_all || verifier_mode > MONO_VERIFIER_MODE_OFF;
5917 }
5918
5919 gboolean
5920 mono_verifier_is_method_full_trust (MonoMethod *method)
5921 {
5922         return mono_verifier_is_class_full_trust (method->klass);
5923 }
5924
5925 /*
5926  * Returns if @klass is under full trust or not.
5927  * 
5928  * TODO This code doesn't take CAS into account.
5929  * 
5930  * Under verify_all all user code must be verifiable if no security option was set 
5931  * 
5932  */
5933 gboolean
5934 mono_verifier_is_class_full_trust (MonoClass *klass)
5935 {
5936         /* under CoreCLR code is trusted if it is part of the "platform" otherwise all code inside the GAC is trusted */
5937         gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ? 
5938                 klass->image->assembly->in_gac : mono_security_core_clr_is_platform_image (klass->image);
5939
5940         if (verify_all && verifier_mode == MONO_VERIFIER_MODE_OFF)
5941                 return trusted_location || klass->image == mono_defaults.corlib;
5942         return verifier_mode < MONO_VERIFIER_MODE_VERIFIABLE || trusted_location || klass->image == mono_defaults.corlib;
5943 }
5944
5945 GSList*
5946 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility)
5947 {
5948         return mono_method_verify (method, 
5949                         (verifier_mode != MONO_VERIFIER_MODE_STRICT ? MONO_VERIFY_NON_STRICT: 0)
5950                         | (!mono_verifier_is_method_full_trust (method) ? MONO_VERIFY_FAIL_FAST : 0)
5951                         | (skip_visibility ? MONO_VERIFY_SKIP_VISIBILITY : 0));
5952 }
5953
5954 static int
5955 get_field_end (MonoClassField *field)
5956 {
5957         int align;
5958         int size = mono_type_size (field->type, &align);
5959         if (size == 0)
5960                 size = 4; /*FIXME Is this a safe bet?*/
5961         return size + field->offset;
5962 }
5963
5964 static gboolean
5965 verify_class_for_overlapping_reference_fields (MonoClass *class)
5966 {
5967         int i, j;
5968         gboolean is_fulltrust = mono_verifier_is_class_full_trust (class);
5969         if (!((class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || !class->has_references)
5970                 return TRUE;
5971                 
5972                 //we must check for stuff overlapping reference fields
5973         for (i = 0; i < class->field.count; ++i) {
5974                 MonoClassField *field = &class->fields [i];
5975                 int fieldEnd = get_field_end (field);
5976                 gboolean is_valuetype = !MONO_TYPE_IS_REFERENCE (field->type);
5977                 if (mono_field_is_deleted (field) || (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
5978                         continue;
5979
5980                 for (j = i + 1; j < class->field.count; ++j) {
5981                         MonoClassField *other = &class->fields [j];
5982                         int otherEnd = get_field_end (other);
5983                         if (mono_field_is_deleted (other) || (is_valuetype && !MONO_TYPE_IS_REFERENCE (other->type)) || (other->type->attrs & FIELD_ATTRIBUTE_STATIC))
5984                                 continue;
5985
5986                         if (!is_valuetype && MONO_TYPE_IS_REFERENCE (other->type) && field->offset == other->offset && is_fulltrust)
5987                                 continue;
5988
5989                         if ((otherEnd > field->offset && otherEnd <= fieldEnd) || (other->offset >= field->offset && other->offset < fieldEnd))
5990                                 return FALSE;
5991                 }
5992         }
5993         return TRUE;
5994 }
5995
5996 static guint
5997 field_hash (gconstpointer key)
5998 {
5999         const MonoClassField *field = key;
6000         return g_str_hash (field->name) ^ mono_metadata_type_hash (field->type); /**/
6001 }
6002
6003 static gboolean
6004 field_equals (gconstpointer _a, gconstpointer _b)
6005 {
6006         const MonoClassField *a = _a;
6007         const MonoClassField *b = _b;
6008         return !strcmp (a->name, b->name) && mono_metadata_type_equal (a->type, b->type);
6009 }
6010
6011
6012 static gboolean
6013 verify_class_fields (MonoClass *class)
6014 {
6015         gpointer iter = NULL;
6016         MonoClassField *field;
6017         MonoGenericContext *context = mono_class_get_context (class);
6018         GHashTable *unique_fields = g_hash_table_new_full (&field_hash, &field_equals, NULL, NULL);
6019         if (class->generic_container)
6020                 context = &class->generic_container->context;
6021
6022         while ((field = mono_class_get_fields (class, &iter)) != NULL) {
6023                 if (!mono_type_is_valid_type_in_context (field->type, context)) {
6024                         g_hash_table_destroy (unique_fields);
6025                         return FALSE;
6026                 }
6027                 if (g_hash_table_lookup (unique_fields, field)) {
6028                         g_hash_table_destroy (unique_fields);
6029                         return FALSE;
6030                 }
6031                 g_hash_table_insert (unique_fields, field, field);
6032         }
6033         g_hash_table_destroy (unique_fields);
6034         return TRUE;
6035 }
6036
6037 static gboolean
6038 verify_interfaces (MonoClass *class)
6039 {
6040         int i;
6041         for (i = 0; i < class->interface_count; ++i) {
6042                 MonoClass *iface = class->interfaces [i];
6043                 if (!(iface->flags & TYPE_ATTRIBUTE_INTERFACE))
6044                         return FALSE;
6045         }
6046         return TRUE;
6047 }
6048
6049 static gboolean
6050 verify_valuetype_layout_with_target (MonoClass *class, MonoClass *target_class)
6051 {
6052         int type;
6053         gpointer iter = NULL;
6054         MonoClassField *field;
6055         MonoClass *field_class;
6056
6057         if (!class->valuetype)
6058                 return TRUE;
6059
6060         type = class->byval_arg.type;
6061         /*primitive type fields are not properly decoded*/
6062         if ((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_R8) || (type >= MONO_TYPE_I && type <= MONO_TYPE_U))
6063                 return TRUE;
6064
6065         while ((field = mono_class_get_fields (class, &iter)) != NULL) {
6066                 if (!field->type)
6067                         return FALSE;
6068
6069                 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
6070                         continue;
6071
6072                 field_class = mono_class_get_generic_type_definition (mono_class_from_mono_type (field->type));
6073
6074                 if (field_class == target_class || !verify_valuetype_layout_with_target (field_class, target_class))
6075                         return FALSE;
6076         }
6077
6078         return TRUE;
6079 }
6080
6081 static gboolean
6082 verify_valuetype_layout (MonoClass *class)
6083 {
6084         gboolean res;
6085         res = verify_valuetype_layout_with_target (class, class);
6086         return res;
6087 }
6088
6089 /*
6090  * Check if the class is verifiable.
6091  * 
6092  * Right now there are no conditions that make a class a valid but not verifiable. Both overlapping reference
6093  * field and invalid generic instantiation are fatal errors.
6094  * 
6095  * This method must be safe to be called from mono_class_init and all code must be carefull about that.
6096  * 
6097  */
6098 gboolean
6099 mono_verifier_verify_class (MonoClass *class)
6100 {
6101         if (class->generic_container && (class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT)
6102                 return FALSE;
6103         if (!verify_class_for_overlapping_reference_fields (class))
6104                 return FALSE;
6105         if (class->generic_class && !mono_class_is_valid_generic_instantiation (NULL, class))
6106                 return FALSE;
6107         if (class->generic_class == NULL && !verify_class_fields (class))
6108                 return FALSE;
6109         if (class->valuetype && !verify_valuetype_layout (class))
6110                 return FALSE;
6111         if (!verify_interfaces (class))
6112                 return FALSE;
6113         return TRUE;
6114 }
6115 #else
6116
6117 gboolean
6118 mono_verifier_verify_class (MonoClass *class)
6119 {
6120         /* The verifier was disabled at compile time */
6121         return TRUE;
6122 }
6123
6124 GSList*
6125 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility)
6126 {
6127         /* The verifier was disabled at compile time */
6128         return NULL;
6129 }
6130
6131 gboolean
6132 mono_verifier_is_class_full_trust (MonoClass *klass)
6133 {
6134         /* The verifier was disabled at compile time */
6135         return TRUE;
6136 }
6137
6138 gboolean
6139 mono_verifier_is_method_full_trust (MonoMethod *method)
6140 {
6141         /* The verifier was disabled at compile time */
6142         return TRUE;
6143 }
6144
6145 gboolean
6146 mono_verifier_is_enabled_for_image (MonoImage *image)
6147 {
6148         /* The verifier was disabled at compile time */
6149         return FALSE;
6150 }
6151
6152 gboolean
6153 mono_verifier_is_enabled_for_class (MonoClass *klass)
6154 {
6155         /* The verifier was disabled at compile time */
6156         return FALSE;
6157 }
6158
6159 gboolean
6160 mono_verifier_is_enabled_for_method (MonoMethod *method)
6161 {
6162         /* The verifier was disabled at compile time */
6163         return FALSE;
6164 }
6165
6166 GSList*
6167 mono_method_verify (MonoMethod *method, int level)
6168 {
6169         /* The verifier was disabled at compile time */
6170         return NULL;
6171 }
6172
6173 void
6174 mono_free_verify_list (GSList *list)
6175 {
6176         /* The verifier was disabled at compile time */
6177         /* will always be null if verifier is disabled */
6178 }
6179
6180 GSList*
6181 mono_image_verify_tables (MonoImage *image, int level)
6182 {
6183         /* The verifier was disabled at compile time */
6184         return NULL;
6185 }       
6186 #endif