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