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