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