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