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