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