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