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