2007-12-05 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 #ifdef MONO_VERIFIER_DEBUG
30 #define VERIFIER_DEBUG(code) do { code } while (0)
31 #else
32 #define VERIFIER_DEBUG(code)
33 #endif
34
35 //////////////////////////////////////////////////////////////////
36 #define 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         if (type->byref)
1241                 return type;
1242         return &mono_class_from_mono_type (type)->this_arg;
1243 }
1244
1245
1246 /*Returns the byval version of the supplied MonoType*/
1247 static MonoType*
1248 mono_type_get_type_byval (MonoType *type)
1249 {
1250         if (!type->byref)
1251                 return type;
1252         return &mono_class_from_mono_type (type)->byval_arg;
1253 }
1254
1255 static MonoType*
1256 mono_type_from_stack_slot (ILStackDesc *slot)
1257 {
1258         if (IS_MANAGED_POINTER (slot->stype))
1259                 return mono_type_get_type_byref (slot->type);
1260         return slot->type;
1261 }
1262
1263 /*Stack manipulation code*/
1264
1265 static void
1266 stack_init (VerifyContext *ctx, ILCodeDesc *state) 
1267 {
1268         state->size = 0;
1269         if (!state->stack) {
1270                 state->stack = g_new0 (ILStackDesc, ctx->max_stack);
1271         }
1272 }
1273
1274 static void
1275 stack_copy (ILCodeDesc *to, ILCodeDesc *from)
1276 {
1277         to->size = from->size;
1278         memcpy (to->stack, from->stack, sizeof (ILStackDesc) * from->size);
1279 }
1280
1281 static void
1282 copy_stack_value (ILStackDesc *to, ILStackDesc *from)
1283 {
1284         to->stype = from->stype;
1285         to->type = from->type;
1286 }
1287
1288 static int
1289 check_underflow (VerifyContext *ctx, int size)
1290 {
1291         if (ctx->eval.size < size) {
1292                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack underflow, required %d, but have %d at 0x%04x", size, ctx->eval.size, ctx->ip_offset));
1293                 return 0;
1294         }
1295         return 1;
1296 }
1297
1298 static int
1299 check_overflow (VerifyContext *ctx)
1300 {
1301         if (ctx->eval.size >= ctx->max_stack) {
1302                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have stack-depth %d at 0x%04x", ctx->eval.size + 1, ctx->ip_offset));
1303                 return 0;
1304         }
1305         return 1;
1306 }
1307
1308 static gboolean
1309 check_unmanaged_pointer (VerifyContext *ctx, ILStackDesc *value)
1310 {
1311         if (value->stype == TYPE_PTR) {
1312                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1313                 return 0;
1314         }
1315         return 1;
1316 }
1317
1318 static gboolean
1319 check_unverifiable_type (VerifyContext *ctx, MonoType *type)
1320 {
1321         if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
1322                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1323                 return 0;
1324         }
1325         return 1;
1326 }
1327
1328
1329 static ILStackDesc *
1330 stack_push (VerifyContext *ctx)
1331 {
1332         return & ctx->eval.stack [ctx->eval.size++];
1333 }
1334
1335 static ILStackDesc *
1336 stack_push_val (VerifyContext *ctx, int stype, MonoType *type)
1337 {
1338         ILStackDesc *top = stack_push (ctx);
1339         top->stype = stype;
1340         top->type = type;
1341         return top;
1342 }
1343
1344 static ILStackDesc *
1345 stack_pop (VerifyContext *ctx)
1346 {
1347         return ctx->eval.stack + --ctx->eval.size;
1348 }
1349
1350 static inline ILStackDesc *
1351 stack_top (VerifyContext *ctx)
1352 {
1353         return ctx->eval.stack + (ctx->eval.size - 1);
1354 }
1355
1356 static inline ILStackDesc *
1357 stack_get (VerifyContext *ctx, int distance)
1358 {
1359         return ctx->eval.stack + (ctx->eval.size - distance - 1);
1360 }
1361
1362 /* Returns the MonoType associated with the token, or NULL if it is invalid.
1363  * 
1364  * A boxable type can be either a reference or value type, but cannot be a byref type or an unmanaged pointer   
1365  * */
1366 static MonoType*
1367 get_boxable_mono_type (VerifyContext* ctx, int token)
1368 {
1369         MonoType *type = mono_type_get_full (ctx->image, token, ctx->generic_context);
1370
1371         if (!type) {
1372                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
1373                 return NULL;
1374         }
1375
1376         if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
1377                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type at 0x%04x", ctx->ip_offset));
1378                 return NULL;
1379         }
1380
1381         if (type->type == MONO_TYPE_TYPEDBYREF) {
1382                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid use of typedbyref at 0x%04x", ctx->ip_offset));
1383                 return NULL;
1384         }
1385
1386         check_unverifiable_type (ctx, type);
1387         return type;
1388 }
1389
1390
1391 /*operation result tables */
1392
1393 static const unsigned char bin_op_table [TYPE_MAX][TYPE_MAX] = {
1394         {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1395         {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1396         {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1397         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1398         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1399         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1400 };
1401
1402 static const unsigned char add_table [TYPE_MAX][TYPE_MAX] = {
1403         {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1404         {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1405         {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1406         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1407         {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1408         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1409 };
1410
1411 static const unsigned char sub_table [TYPE_MAX][TYPE_MAX] = {
1412         {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1413         {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1414         {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1415         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1416         {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1417         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1418 };
1419
1420 static const unsigned char int_bin_op_table [TYPE_MAX][TYPE_MAX] = {
1421         {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1422         {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1423         {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1424         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1425         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1426         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1427 };
1428
1429 static const unsigned char shift_op_table [TYPE_MAX][TYPE_MAX] = {
1430         {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1431         {TYPE_I8, TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV},
1432         {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1433         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1434         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1435         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1436 };
1437
1438 static const unsigned char cmp_br_op [TYPE_MAX][TYPE_MAX] = {
1439         {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1440         {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1441         {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1442         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1443         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV},
1444         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1445 };
1446
1447 static const unsigned char cmp_br_eq_op [TYPE_MAX][TYPE_MAX] = {
1448         {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1449         {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1450         {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV},
1451         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1452         {TYPE_INV, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_I4, TYPE_INV},
1453         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4},
1454 };
1455
1456 /*debug helpers */
1457 static void
1458 dump_stack_value (ILStackDesc *value)
1459 {
1460         printf ("[(%d)(%d)", value->type->type, value->stype);
1461
1462         if (value->stype & CMMP_MASK)
1463                 printf ("Controled Mutability MP: ");
1464
1465         if (IS_MANAGED_POINTER (value->stype))
1466                 printf ("Managed Pointer to: ");
1467
1468         switch (UNMASK_TYPE (value->stype)) {
1469                 case TYPE_INV:
1470                         printf ("invalid type]"); 
1471                         return;
1472                 case TYPE_I4:
1473                         printf ("int32]"); 
1474                         return;
1475                 case TYPE_I8:
1476                         printf ("int64]"); 
1477                         return;
1478                 case TYPE_NATIVE_INT:
1479                         printf ("native int]"); 
1480                         return;
1481                 case TYPE_R8:
1482                         printf ("float64]"); 
1483                         return;
1484                 case TYPE_PTR:
1485                         printf ("unmanaged pointer]"); 
1486                         return;
1487                 case TYPE_COMPLEX:
1488                         switch (value->type->type) {
1489                         case MONO_TYPE_CLASS:
1490                         case MONO_TYPE_VALUETYPE:
1491                                 printf ("complex] (%s)", value->type->data.klass->name);
1492                                 return;
1493                         case MONO_TYPE_STRING:
1494                                 printf ("complex] (string)");
1495                                 return;
1496                         case MONO_TYPE_OBJECT:
1497                                 printf ("complex] (object)");
1498                                 return;
1499                         case MONO_TYPE_SZARRAY:
1500                                 printf ("complex] (%s [])", value->type->data.klass->name);
1501                                 return;
1502                         case MONO_TYPE_ARRAY:
1503                                 printf ("complex] (%s [%d %d %d])",
1504                                         value->type->data.array->eklass->name,
1505                                         value->type->data.array->rank,
1506                                         value->type->data.array->numsizes,
1507                                         value->type->data.array->numlobounds);
1508                                 return;
1509                         case MONO_TYPE_GENERICINST:
1510                                 printf ("complex] (inst of %s )", value->type->data.generic_class->container_class->name);
1511                                 return;
1512                         case MONO_TYPE_VAR:
1513                                 printf ("complex] (type generic param !%d - %s) ", value->type->data.generic_param->num, value->type->data.generic_param->name);
1514                                 return;
1515                         case MONO_TYPE_MVAR:
1516                                 printf ("complex] (method generic param !!%d - %s) ", value->type->data.generic_param->num, value->type->data.generic_param->name);
1517                                 return;
1518                         default:
1519                                 printf ("unknown complex %d type]\n", value->type->type);
1520                                 g_assert_not_reached ();
1521                         }
1522                 default:
1523                         printf ("unknown stack %d type]\n", value->stype);
1524                         g_assert_not_reached ();
1525         }
1526 }
1527
1528 static void
1529 dump_stack_state (ILCodeDesc *state) 
1530 {
1531         int i;
1532
1533         printf ("(%d) ", state->size);
1534         for (i = 0; i < state->size; ++i)
1535                 dump_stack_value (state->stack + i);
1536         printf ("\n");
1537 }
1538
1539 static void
1540 dump_context (VerifyContext *ctx, int code_size)
1541 {
1542         int i;
1543
1544         for (i = 0; i < code_size; ++i) {
1545                 if (ctx->code [i].flags & IL_CODE_FLAG_SEEN) {
1546                         printf ("opcode [%d]:\n\t", i);
1547                         dump_stack_state (&ctx->code [i]);
1548                 }
1549         }
1550 }
1551
1552 /*Returns TRUE if candidate array type can be assigned to target.
1553  *Both parameters MUST be of type MONO_TYPE_ARRAY (target->type == MONO_TYPE_ARRAY)
1554  */
1555 static gboolean
1556 is_array_type_compatible (MonoType *target, MonoType *candidate)
1557 {
1558         int i;
1559         MonoArrayType *left = target->data.array;
1560         MonoArrayType *right = candidate->data.array;
1561
1562         g_assert (target->type == MONO_TYPE_ARRAY);
1563         g_assert (candidate->type == MONO_TYPE_ARRAY);
1564
1565
1566         if ((left->rank != right->rank) ||
1567                         (left->numsizes != right->numsizes) ||
1568                         (left->numlobounds != right->numlobounds))
1569                 return FALSE;
1570
1571         for (i = 0; i < left->numsizes; ++i) 
1572                 if (left->sizes [i] != right->sizes [i])
1573                         return FALSE;
1574
1575         for (i = 0; i < left->numlobounds; ++i) 
1576                 if (left->lobounds [i] != right->lobounds [i])
1577                         return FALSE;
1578
1579         return mono_class_is_assignable_from (left->eklass, right->eklass);
1580 }
1581
1582 static int
1583 get_stack_type (MonoType *type)
1584 {
1585         int mask = 0;
1586         int type_kind = type->type;
1587         if (type->byref)
1588                 mask = POINTER_MASK;
1589         /*TODO handle CMMP_MASK */
1590
1591 handle_enum:
1592         switch (type_kind) {
1593         case MONO_TYPE_I1:
1594         case MONO_TYPE_U1:
1595         case MONO_TYPE_BOOLEAN:
1596         case MONO_TYPE_I2:
1597         case MONO_TYPE_U2:
1598         case MONO_TYPE_CHAR:
1599         case MONO_TYPE_I4:
1600         case MONO_TYPE_U4:
1601                 return TYPE_I4 | mask;
1602
1603         case MONO_TYPE_I:
1604         case MONO_TYPE_U:
1605                 return TYPE_NATIVE_INT | mask;
1606
1607         /* FIXME: the spec says that you cannot have a pointer to method pointer, do we need to check this here? */ 
1608         case MONO_TYPE_FNPTR:
1609         case MONO_TYPE_PTR:
1610         case MONO_TYPE_TYPEDBYREF:
1611                 return TYPE_PTR | mask;
1612
1613         case MONO_TYPE_CLASS:
1614         case MONO_TYPE_STRING:
1615         case MONO_TYPE_OBJECT:
1616         case MONO_TYPE_SZARRAY:
1617         case MONO_TYPE_ARRAY:
1618         case MONO_TYPE_GENERICINST:
1619                 return TYPE_COMPLEX | mask;
1620
1621         case MONO_TYPE_I8:
1622         case MONO_TYPE_U8:
1623                 return TYPE_I8 | mask;
1624
1625         case MONO_TYPE_R4:
1626         case MONO_TYPE_R8:
1627                 return TYPE_R8 | mask;
1628
1629         case MONO_TYPE_VALUETYPE:
1630                 if (type->data.klass->enumtype) {
1631                         type = type->data.klass->enum_basetype;
1632                         type_kind = type->type;
1633                         goto handle_enum;
1634                 } else 
1635                         return TYPE_COMPLEX | mask;
1636
1637         default:
1638                 VERIFIER_DEBUG ( printf ("unknown type %02x in eval stack type\n", type->type); );
1639                 g_assert_not_reached ();
1640                 return 0;
1641         }
1642 }
1643
1644 /* convert MonoType to ILStackDesc format (stype) */
1645 static void
1646 set_stack_value (ILStackDesc *stack, MonoType *type, int take_addr)
1647 {
1648         int mask = 0;
1649         int type_kind = type->type;
1650
1651         if (type->byref || take_addr)
1652                 mask = POINTER_MASK;
1653         /* TODO handle CMMP_MASK */
1654
1655 handle_enum:
1656         stack->type = type;
1657
1658         switch (type_kind) {
1659         case MONO_TYPE_I1:
1660         case MONO_TYPE_U1:
1661         case MONO_TYPE_BOOLEAN:
1662         case MONO_TYPE_I2:
1663         case MONO_TYPE_U2:
1664         case MONO_TYPE_CHAR:
1665         case MONO_TYPE_I4:
1666         case MONO_TYPE_U4:
1667                 stack->stype = TYPE_I4 | mask;
1668                 return;
1669         case MONO_TYPE_I:
1670         case MONO_TYPE_U:
1671                 stack->stype = TYPE_NATIVE_INT | mask;
1672                 return;
1673
1674         /*FIXME: Do we need to check if it's a pointer to the method pointer? The spec says it' illegal to have that.*/
1675         case MONO_TYPE_FNPTR:
1676         case MONO_TYPE_PTR:
1677         case MONO_TYPE_TYPEDBYREF:
1678                 stack->stype = TYPE_PTR | mask;
1679                 return;
1680
1681         case MONO_TYPE_CLASS:
1682         case MONO_TYPE_STRING:
1683         case MONO_TYPE_OBJECT:
1684         case MONO_TYPE_SZARRAY:
1685         case MONO_TYPE_ARRAY:
1686
1687         case MONO_TYPE_GENERICINST:
1688         case MONO_TYPE_VAR:
1689         case MONO_TYPE_MVAR: 
1690                 stack->stype = TYPE_COMPLEX | mask;
1691                 return;
1692         case MONO_TYPE_I8:
1693         case MONO_TYPE_U8:
1694                 stack->stype = TYPE_I8 | mask;
1695                 return;
1696         case MONO_TYPE_R4:
1697         case MONO_TYPE_R8:
1698                 stack->stype = TYPE_R8 | mask;
1699                 return;
1700         case MONO_TYPE_VALUETYPE:
1701                 if (type->data.klass->enumtype) {
1702                         type = type->data.klass->enum_basetype;
1703                         type_kind = type->type;
1704                         goto handle_enum;
1705                 } else {
1706                         stack->stype = TYPE_COMPLEX | mask;
1707                         return;
1708                 }
1709         default:
1710                 VERIFIER_DEBUG ( printf ("unknown type 0x%02x in eval stack type\n", type->type); );
1711                 g_assert_not_reached ();
1712         }
1713         return;
1714 }
1715
1716 /* Generics validation stuff, should be moved to another metadata/? file */
1717 static gboolean
1718 mono_is_generic_type_compatible (MonoType *target, MonoType *candidate)
1719 {
1720         if (target->byref != candidate->byref)
1721                 return FALSE;
1722
1723 handle_enum:
1724         switch (target->type) {
1725         case MONO_TYPE_STRING:
1726                 if (candidate->type == MONO_TYPE_STRING)
1727                         return TRUE;
1728                 return FALSE;
1729
1730         case MONO_TYPE_CLASS:
1731                 if (candidate->type != MONO_TYPE_CLASS)
1732                         return FALSE;
1733
1734                 VERIFIER_DEBUG ( printf ("verifying type class %p %p\n", target->data.klass, candidate->data.klass); );
1735                 return mono_class_is_assignable_from (target->data.klass, candidate->data.klass);
1736
1737         case MONO_TYPE_OBJECT:
1738                 return MONO_TYPE_IS_REFERENCE (candidate);
1739
1740         case MONO_TYPE_SZARRAY:
1741                 if (candidate->type != MONO_TYPE_SZARRAY)
1742                         return FALSE;
1743                 return mono_class_is_assignable_from (target->data.klass, candidate->data.klass);
1744
1745         case MONO_TYPE_VALUETYPE:
1746                 if (target->data.klass->enumtype) {
1747                         target = target->data.klass->enum_basetype;
1748                         goto handle_enum;
1749                 } else {
1750                         if (candidate->type != MONO_TYPE_VALUETYPE)
1751                                 return FALSE;
1752                         return candidate->data.klass == target->data.klass;
1753                 }
1754
1755         case MONO_TYPE_ARRAY:
1756                 if (candidate->type != MONO_TYPE_ARRAY)
1757                         return FALSE;
1758                 return is_array_type_compatible (target, candidate);
1759
1760         default:
1761                 VERIFIER_DEBUG ( printf ("unknown target type %d\n", target->type); );
1762                 g_assert_not_reached ();
1763         }
1764
1765         return FALSE;
1766 }
1767
1768
1769 static gboolean
1770 mono_is_generic_instance_compatible (MonoGenericClass *target, MonoGenericClass *candidate, MonoGenericClass *root_candidate) {
1771         MonoGenericContainer *container;
1772         int i;
1773
1774         VERIFIER_DEBUG ( printf ("candidate container %p\n", candidate->container_class->generic_container); );
1775         if (target->container_class != candidate->container_class) {
1776                 MonoType *param_class;
1777                 MonoClass *cand_class;
1778                 VERIFIER_DEBUG ( printf ("generic class != target\n"); );
1779                 param_class = candidate->context.class_inst->type_argv [0];
1780                 VERIFIER_DEBUG ( printf ("param 0 %d\n", param_class->type); );
1781                 cand_class = candidate->container_class;
1782
1783                 /* We must check if it's an interface type*/
1784                 if (MONO_CLASS_IS_INTERFACE (target->container_class)) {
1785                         VERIFIER_DEBUG ( printf ("generic type is an interface\n"); );
1786
1787                         do {
1788                                 int iface_count = cand_class->interface_count;
1789                                 MonoClass **ifaces = cand_class->interfaces;
1790                                 int i;
1791                                 VERIFIER_DEBUG ( printf ("type has %d interfaces\n", iface_count); );
1792                                 for (i = 0; i< iface_count; ++i) {
1793                                         MonoClass *ifc = ifaces[i];
1794                                         VERIFIER_DEBUG ( printf ("analysing %s\n", ifc->name); );
1795                                         if (ifc->generic_class) {
1796                                                 VERIFIER_DEBUG ( printf ("interface has generic info\n"); );
1797                                         }
1798                                         if (mono_is_generic_instance_compatible (target, ifc->generic_class, root_candidate)) {
1799                                                 VERIFIER_DEBUG ( printf ("we got compatible stuff!\n"); );
1800                                                 return TRUE;
1801                                         }
1802                                 }
1803
1804                                 cand_class = cand_class->parent;
1805                         } while (cand_class);
1806
1807                         VERIFIER_DEBUG ( printf ("don't implements an interface\n"); );
1808
1809                 } else {
1810                         VERIFIER_DEBUG ( printf ("verifying upper classes\n"); );
1811
1812                         cand_class = cand_class->parent;
1813
1814                         while (cand_class) {
1815                                 VERIFIER_DEBUG ( printf ("verifying parent class name %s\n", cand_class->name); );      
1816                                 if (cand_class->generic_class) {
1817                                         VERIFIER_DEBUG ( printf ("super type has generic context\n"); );
1818
1819                                         /* TODO break loop if target->container_class == cand_class->generic_class->container_class */
1820                                         return mono_is_generic_instance_compatible (target, cand_class->generic_class, root_candidate);
1821                                 } else
1822                                         VERIFIER_DEBUG ( printf ("super class has no generic context\n"); );
1823                                 cand_class = cand_class->parent;
1824                         }
1825                 }
1826                 return FALSE;
1827         }
1828
1829         /* now we verify if the instantiations are compatible*/ 
1830         if (target->context.class_inst == candidate->context.class_inst) {
1831                 VERIFIER_DEBUG ( printf ("generic types are compatible, both have the same instantiation\n"); );
1832                 return TRUE;
1833         }
1834
1835         if (target->context.class_inst->type_argc != candidate->context.class_inst->type_argc) {
1836                 VERIFIER_DEBUG ( printf ("generic instantiations with different arg counts\n"); );
1837                 return FALSE;
1838         }
1839
1840         //verify if open instance -- none should be 
1841
1842         container = target->container_class->generic_container;
1843
1844         for (i = 0; i < container->type_argc; ++i) {
1845                 MonoGenericParam *param = container->type_params + i;
1846                 MonoType *target_type = target->context.class_inst->type_argv [i];
1847                 MonoType *candidate_type = candidate->context.class_inst->type_argv [i];
1848                 /* We resolve TYPE_VAR types before proceeding */
1849
1850                 if (candidate_type->type == MONO_TYPE_VAR) {
1851                         MonoGenericParam *var_param = candidate_type->data.generic_param;
1852                         candidate_type = root_candidate->context.class_inst->type_argv [var_param->num];
1853                 }
1854
1855                 if ((param->flags & GENERIC_PARAMETER_ATTRIBUTE_VARIANCE_MASK) == 0) {
1856                         VERIFIER_DEBUG ( printf ("generic type have no variance flag, checking each type %d %d \n",target_type->type, candidate_type->type); );
1857
1858                         if (!mono_metadata_type_equal (target_type, candidate_type))
1859                                 return FALSE;
1860                 } else {
1861                         VERIFIER_DEBUG ( printf ("generic type has variance flag, need to perform deeper check\n"); );
1862                         /* first we check if they are the same kind */
1863                         /* byref generic params are forbiden, but better safe than sorry.*/
1864
1865                         if ((param->flags & GENERIC_PARAMETER_ATTRIBUTE_COVARIANT) == GENERIC_PARAMETER_ATTRIBUTE_COVARIANT) {
1866                                 if (!mono_is_generic_type_compatible (target_type, candidate_type))
1867                                         return FALSE;
1868                         /* the attribute must be contravariant */
1869                         } else if (!mono_is_generic_type_compatible (candidate_type, target_type))
1870                                 return FALSE;
1871                 }
1872         }
1873         return TRUE;
1874 }
1875
1876
1877
1878 /*Verify if type 'candidate' can be stored in type 'target'.
1879  * 
1880  * If strict, check for the underlying type and not the verification stack types
1881  */
1882 static gboolean
1883 verify_type_compatibility_full (VerifyContext *ctx, MonoType *target, MonoType *candidate, gboolean strict)
1884 {
1885 #define IS_ONE_OF3(T, A, B, C) (T == A || T == B || T == C)
1886 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
1887
1888         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); );
1889
1890         /*only one is byref */
1891         if (candidate->byref ^ target->byref) {
1892                 /* converting from native int to byref*/
1893                 if (get_stack_type (candidate) == TYPE_NATIVE_INT && target->byref) {
1894                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("using byref native int at 0x%04x", ctx->ip_offset));
1895                         return TRUE;
1896                 }
1897                 return FALSE;
1898         }
1899         strict |= target->byref;
1900
1901 handle_enum:
1902         switch (target->type) {
1903         case MONO_TYPE_I1:
1904         case MONO_TYPE_U1:
1905         case MONO_TYPE_BOOLEAN:
1906                 if (strict)
1907                         return IS_ONE_OF3 (candidate->type, MONO_TYPE_I1, MONO_TYPE_U1, MONO_TYPE_BOOLEAN);
1908         case MONO_TYPE_I2:
1909         case MONO_TYPE_U2:
1910         case MONO_TYPE_CHAR:
1911                 if (strict)
1912                         return IS_ONE_OF3 (candidate->type, MONO_TYPE_I2, MONO_TYPE_U2, MONO_TYPE_CHAR);
1913         case MONO_TYPE_I4:
1914         case MONO_TYPE_U4: {
1915                 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
1916                 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
1917                 if (strict)
1918                         return is_native_int || is_int4;
1919                 return is_native_int || get_stack_type (candidate) == TYPE_I4;
1920         }
1921
1922         case MONO_TYPE_I8:
1923         case MONO_TYPE_U8:
1924                 return IS_ONE_OF2 (candidate->type, MONO_TYPE_I8, MONO_TYPE_U8);
1925
1926         case MONO_TYPE_R4:
1927         case MONO_TYPE_R8:
1928                 if (strict)
1929                         return candidate->type == target->type;
1930                 return IS_ONE_OF2 (candidate->type, MONO_TYPE_R4, MONO_TYPE_R8);
1931
1932         case MONO_TYPE_I:
1933         case MONO_TYPE_U: {
1934                 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
1935                 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
1936                 if (strict)
1937                         return is_native_int || is_int4;
1938                 return is_native_int || get_stack_type (candidate) == TYPE_I4;
1939         }
1940
1941         case MONO_TYPE_PTR:
1942                 if (candidate->type != MONO_TYPE_PTR)
1943                         return FALSE;
1944                 /* check the underlying type */
1945                 return verify_type_compatibility_full (ctx, target->data.type, candidate->data.type, TRUE);
1946
1947         case MONO_TYPE_FNPTR: {
1948                 MonoMethodSignature *left, *right;
1949                 if (candidate->type != MONO_TYPE_FNPTR)
1950                         return FALSE;
1951
1952                 left = mono_type_get_signature (target);
1953                 right = mono_type_get_signature (candidate);
1954                 return mono_metadata_signature_equal (left, right) && left->call_convention == right->call_convention;
1955         }
1956
1957         case MONO_TYPE_GENERICINST: {
1958                 MonoGenericClass *left;
1959                 MonoGenericClass *right;
1960                 if (candidate->type != MONO_TYPE_GENERICINST)
1961                         return FALSE;
1962                 left = target->data.generic_class;
1963                 right = candidate->data.generic_class;
1964
1965                 return mono_is_generic_instance_compatible (left, right, right);
1966         }
1967
1968         case MONO_TYPE_STRING:
1969                 return candidate->type == MONO_TYPE_STRING;
1970
1971         case MONO_TYPE_CLASS:
1972                 return mono_class_is_assignable_from (target->data.klass, mono_class_from_mono_type (candidate));
1973
1974         case MONO_TYPE_OBJECT:
1975                 return MONO_TYPE_IS_REFERENCE (candidate);
1976
1977         case MONO_TYPE_SZARRAY: {
1978                 MonoClass *left;
1979                 MonoClass *right;
1980                 if (candidate->type != MONO_TYPE_SZARRAY)
1981                         return FALSE;
1982
1983                 left = target->data.klass;
1984                 right = candidate->data.klass;
1985                 return mono_class_is_assignable_from(left, right);
1986         }
1987
1988         case MONO_TYPE_ARRAY:
1989                 if (candidate->type != MONO_TYPE_ARRAY)
1990                         return FALSE;
1991                 return is_array_type_compatible (target, candidate);
1992
1993         //TODO verify aditional checks that needs to be done
1994         case MONO_TYPE_TYPEDBYREF:
1995                 return candidate->type == MONO_TYPE_TYPEDBYREF;
1996
1997         case MONO_TYPE_VALUETYPE:
1998                 if (target->data.klass->enumtype) {
1999                         target = target->data.klass->enum_basetype;
2000                         goto handle_enum;
2001                 } else {
2002                         if (candidate->type != MONO_TYPE_VALUETYPE)
2003                                 return FALSE;
2004                         return target->data.klass == candidate->data.klass;
2005                 }
2006                 
2007         case MONO_TYPE_VAR:
2008                 if (candidate->type != MONO_TYPE_VAR)
2009                         return FALSE;
2010                 return candidate->data.generic_param->num == target->data.generic_param->num;
2011
2012         case MONO_TYPE_MVAR:
2013                 if (candidate->type != MONO_TYPE_MVAR)
2014                         return FALSE;
2015                 return candidate->data.generic_param->num == target->data.generic_param->num;
2016
2017         default:
2018                 VERIFIER_DEBUG ( printf ("unknown store type %d\n", target->type); );
2019                 g_assert_not_reached ();
2020                 return FALSE;
2021         }
2022         return 1;
2023 #undef IS_ONE_OF3
2024 #undef IS_ONE_OF2
2025 }
2026
2027 static gboolean
2028 verify_type_compatibility (VerifyContext *ctx, MonoType *target, MonoType *candidate)
2029 {
2030         return verify_type_compatibility_full (ctx, target, candidate, FALSE);
2031 }
2032
2033
2034 static int
2035 verify_stack_type_compatibility (VerifyContext *ctx, MonoType *type, ILStackDesc *stack)
2036 {
2037         return verify_type_compatibility_full (ctx, type, mono_type_from_stack_slot (stack), FALSE);
2038 }
2039
2040 /* implement the opcode checks*/
2041 static void
2042 push_arg (VerifyContext *ctx, unsigned int arg, int take_addr) 
2043 {
2044         if (arg >= ctx->max_args) {
2045                 if (take_addr) 
2046                         ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2047                 else {
2048                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2049                         if (check_overflow (ctx)) //FIXME: what sane value could we ever push?
2050                                 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
2051                 }
2052         } else if (check_overflow (ctx)) {
2053                 /*We must let the value be pushed, otherwise we would get an underflow error*/
2054                 check_unverifiable_type (ctx, ctx->params [arg]);
2055                 if (ctx->params [arg]->byref && take_addr)
2056                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2057                 set_stack_value (stack_push (ctx), ctx->params [arg], take_addr);
2058         } 
2059 }
2060
2061 static void
2062 push_local (VerifyContext *ctx, guint32 arg, int take_addr) 
2063 {
2064         if (arg >= ctx->num_locals) {
2065                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local %d", arg + 1));
2066         } else if (check_overflow (ctx)) {
2067                 /*We must let the value be pushed, otherwise we would get an underflow error*/
2068                 check_unverifiable_type (ctx, ctx->locals [arg]);
2069                 if (ctx->locals [arg]->byref && take_addr)
2070                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2071
2072                 set_stack_value (stack_push (ctx), ctx->locals [arg], take_addr);
2073         } 
2074 }
2075
2076 static void
2077 store_arg (VerifyContext *ctx, guint32 arg)
2078 {
2079         ILStackDesc *value;
2080
2081         if (arg >= ctx->max_args) {
2082                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", arg + 1, ctx->ip_offset));
2083                 check_underflow (ctx, 1);
2084                 stack_pop (ctx);
2085                 return;
2086         }
2087
2088         if (check_underflow (ctx, 1)) {
2089                 value = stack_pop (ctx);
2090                 if (!verify_stack_type_compatibility (ctx, ctx->params [arg], value)) {
2091                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in argument store at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
2092                 }
2093         }
2094 }
2095
2096 static void
2097 store_local (VerifyContext *ctx, guint32 arg)
2098 {
2099         ILStackDesc *value;
2100         if (arg >= ctx->num_locals) {
2101                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", arg + 1, ctx->ip_offset));
2102                 return;
2103         }
2104
2105         /*TODO verify definite assigment */             
2106         if (check_underflow (ctx, 1)) {
2107                 value = stack_pop(ctx);
2108                 if (!verify_stack_type_compatibility (ctx, ctx->locals [arg], value)) {
2109                         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));  
2110                 }
2111         }
2112 }
2113
2114 static void
2115 do_binop (VerifyContext *ctx, unsigned int opcode, const unsigned char table [TYPE_MAX][TYPE_MAX])
2116 {
2117         ILStackDesc *a, *b;
2118         int idxa, idxb, complexMerge = 0;
2119         unsigned char res;
2120
2121         if (!check_underflow (ctx, 2))
2122                 return;
2123         a = stack_get (ctx, 1);
2124         b = stack_top (ctx);
2125
2126         idxa = a->stype;
2127         if (IS_MANAGED_POINTER (idxa)) {
2128                 idxa = TYPE_PTR;
2129                 complexMerge = 1;
2130         }
2131
2132         idxb = b->stype;
2133         if (IS_MANAGED_POINTER (idxb)) {
2134                 idxb = TYPE_PTR;
2135                 complexMerge = 2;
2136         }
2137
2138         --idxa;
2139         --idxb;
2140         res = table [idxa][idxb];
2141
2142         VERIFIER_DEBUG ( printf ("binop res %d\n", res); );
2143         VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
2144
2145         ctx->eval.size--;
2146         if (res == TYPE_INV) {
2147                 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)]));
2148                 return;
2149         }
2150
2151         if (res & NON_VERIFIABLE_RESULT) {
2152                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Binary instruction is not verifiable (%s x %s)", 
2153                         type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)]));
2154
2155                 res = res & ~NON_VERIFIABLE_RESULT;
2156         }
2157
2158         if (complexMerge && res == TYPE_PTR) {
2159                 if (complexMerge == 1) 
2160                         copy_stack_value (stack_top (ctx), a);
2161                 else if (complexMerge == 2)
2162                         copy_stack_value (stack_top (ctx), b);
2163                 /*
2164                  * There is no need to merge the type of two pointers.
2165                  * The only valid operation is subtraction, that returns a native
2166                  *  int as result and can be used with any 2 pointer kinds.
2167                  * This is valid acording to Patition III 1.1.4
2168                  */
2169         } else
2170                 stack_top (ctx)->stype = res;
2171         
2172 }
2173
2174
2175 static void
2176 do_boolean_branch_op (VerifyContext *ctx, int delta)
2177 {
2178         int target = ctx->ip_offset + delta;
2179         ILStackDesc *top;
2180
2181         VERIFIER_DEBUG ( printf ("boolean branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
2182  
2183         if (target < 0 || target >= ctx->code_size) {
2184                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Boolean branch target out of code at 0x%04x", ctx->ip_offset));
2185                 return;
2186         }
2187
2188         if (!in_same_block (ctx->header, ctx->ip_offset, target)) {
2189                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2190                 return;
2191         }
2192
2193         ctx->target = target;
2194
2195         if (!check_underflow (ctx, 1))
2196                 return;
2197
2198         top = stack_pop (ctx);
2199         if (!is_valid_bool_arg (top))
2200                 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));
2201
2202         check_unmanaged_pointer (ctx, top);
2203 }
2204
2205
2206 static void
2207 do_branch_op (VerifyContext *ctx, signed int delta, const unsigned char table [TYPE_MAX][TYPE_MAX])
2208 {
2209         ILStackDesc *a, *b;
2210         int idxa, idxb;
2211         unsigned char res;
2212         int target = ctx->ip_offset + delta;
2213
2214         VERIFIER_DEBUG ( printf ("branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
2215  
2216         if (target < 0 || target >= ctx->code_size) {
2217                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
2218                 return;
2219         }
2220
2221         if (!in_same_block (ctx->header, ctx->ip_offset, target)) {
2222                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2223                 return;
2224         }
2225
2226         ctx->target = target;
2227
2228         if (!check_underflow (ctx, 2))
2229                 return;
2230
2231         b = stack_pop (ctx);
2232         a = stack_pop (ctx);
2233
2234         idxa = a->stype;
2235         if (IS_MANAGED_POINTER (idxa))
2236                 idxa = TYPE_PTR;
2237
2238         idxb = b->stype;
2239         if (IS_MANAGED_POINTER (idxb))
2240                 idxb = TYPE_PTR;
2241
2242         --idxa;
2243         --idxb;
2244         res = table [idxa][idxb];
2245
2246         VERIFIER_DEBUG ( printf ("branch res %d\n", res); );
2247         VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
2248
2249         if (res == TYPE_INV) {
2250                 ADD_VERIFY_ERROR (ctx,
2251                         g_strdup_printf ("Compare and Branch instruction applyed to ill formed stack (%s x %s) at 0x%04x",
2252                                 type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)], ctx->ip_offset));
2253         } else if (res & NON_VERIFIABLE_RESULT) {
2254                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Compare and Branch instruction is not verifiable (%s x %s) at 0x%04x",
2255                                 type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)], ctx->ip_offset)); 
2256                 res = res & ~NON_VERIFIABLE_RESULT;
2257         }
2258 }
2259
2260 static void
2261 do_cmp_op (VerifyContext *ctx, const unsigned char table [TYPE_MAX][TYPE_MAX])
2262 {
2263         ILStackDesc *a, *b;
2264         int idxa, idxb;
2265         unsigned char res;
2266
2267         if (!check_underflow (ctx, 2))
2268                 return;
2269         b = stack_pop (ctx);
2270         a = stack_pop (ctx);
2271
2272         idxa = a->stype;
2273         if (IS_MANAGED_POINTER (idxa))
2274                 idxa = TYPE_PTR;
2275
2276         idxb = b->stype;
2277         if (IS_MANAGED_POINTER (idxb)) 
2278                 idxb = TYPE_PTR;
2279
2280         --idxa;
2281         --idxb;
2282         res = table [idxa][idxb];
2283
2284         if(res == TYPE_INV) {
2285                 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));
2286         } else if (res & NON_VERIFIABLE_RESULT) {
2287                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Compare instruction is not verifiable (%s x %s) at 0x%04x",
2288                         type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)], ctx->ip_offset)); 
2289                 res = res & ~NON_VERIFIABLE_RESULT;
2290         }
2291         stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
2292 }
2293
2294 static void
2295 do_ret (VerifyContext *ctx)
2296 {
2297         VERIFIER_DEBUG ( printf ("checking ret\n"); );
2298         if (ctx->signature->ret->type != MONO_TYPE_VOID) {
2299                 ILStackDesc *top;
2300                 if (!check_underflow (ctx, 1))
2301                         return;
2302
2303                 top = stack_pop(ctx);
2304
2305                 if (!verify_stack_type_compatibility (ctx, ctx->signature->ret, top)) {
2306                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible return value on stack with method signature ret at 0x%04x", ctx->ip_offset));
2307                         return;
2308                 }
2309         }
2310
2311         if (ctx->eval.size > 0) {
2312                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack not empty (%d) after ret at 0x%04x", ctx->eval.size, ctx->ip_offset));
2313         } 
2314         if (in_any_block (ctx->header, ctx->ip_offset))
2315                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("ret cannot escape exception blocks at 0x%04x", ctx->ip_offset));
2316 }
2317
2318 /* FIXME: we could just load the signature instead of the whole MonoMethod
2319  * TODO handle vararg calls
2320  * TODO handle non virt calls to non-final virtual calls (from the verifiability clause in page 52 of partition 3)
2321  * TODO handle abstract calls
2322  * TODO handle calling .ctor outside one or calling the .ctor for other class but super
2323  * TODO handle call invoking virtual methods (only allowed to invoke super)  
2324  */
2325 static void
2326 do_invoke_method (VerifyContext *ctx, int method_token)
2327 {
2328         int param_count, i;
2329         MonoMethodSignature *sig;
2330         ILStackDesc *value;
2331         MonoMethod *method = mono_get_method_full (ctx->image, method_token, NULL, ctx->generic_context);
2332
2333         if (!method) {
2334                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method 0x%08x not found at 0x%04x", method_token, ctx->ip_offset));
2335                 return;
2336         }
2337
2338         if (!(sig = mono_method_signature (method)))
2339                 sig = mono_method_get_signature (method, ctx->image, method_token);
2340
2341         param_count = sig->param_count + sig->hasthis;
2342         if (!check_underflow (ctx, param_count))
2343                 return;
2344
2345         for (i = sig->param_count - 1; i >= 0; --i) {
2346                 VERIFIER_DEBUG ( printf ("verifying argument %d\n", i); );
2347                 value = stack_pop (ctx);
2348                 if (!verify_stack_type_compatibility (ctx, sig->params[i], value))
2349                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible parameter value with function signature at 0x%04x", ctx->ip_offset));
2350         }
2351
2352         if (sig->hasthis) {
2353                 MonoType * type = method->klass->valuetype ? &method->klass->this_arg : &method->klass->byval_arg;
2354
2355                 VERIFIER_DEBUG ( printf ("verifying this argument\n"); );
2356                 value = stack_pop (ctx);
2357                 if (!verify_stack_type_compatibility (ctx, type, value)) {
2358                         ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Incompatible this argument on stack with method signature ret at 0x%04x", ctx->ip_offset));
2359                         return;
2360                 }
2361         }
2362         if (!mono_method_can_access_method (ctx->method, method))
2363                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method is not accessible at 0x%04x", ctx->ip_offset));
2364
2365         if (sig->ret->type != MONO_TYPE_VOID) {
2366                 if (check_overflow (ctx))
2367                         set_stack_value (stack_push (ctx), sig->ret, FALSE);
2368         }
2369
2370         if (sig->ret->type == MONO_TYPE_TYPEDBYREF
2371                 || sig->ret->byref
2372                 || (sig->ret->type == MONO_TYPE_VALUETYPE && !strcmp ("System", sig->ret->data.klass->name_space) && !strcmp ("ArgIterator", sig->ret->data.klass->name)))
2373                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method returns typedbyref, byref or ArgIterator at 0x%04x", ctx->ip_offset));
2374 }
2375
2376 static void
2377 do_push_static_field (VerifyContext *ctx, int token, gboolean take_addr)
2378 {
2379         MonoClassField *field;
2380         MonoClass *klass;
2381
2382         field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context);
2383         if (!field) {
2384                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ctx->ip_offset));
2385                 return;
2386         }
2387
2388         if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) { 
2389                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load non static field at 0x%04x", ctx->ip_offset));
2390                 return;
2391         }
2392         /*taking the address of initonly field only works from the static constructor */
2393         if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
2394                 !(field->parent == ctx->method->klass && (ctx->method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_STATIC)) && !strcmp (".cctor", ctx->method->name)))
2395                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
2396
2397         if (!mono_method_can_access_field (ctx->method, field))
2398                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset));
2399
2400         set_stack_value (stack_push (ctx), field->type, take_addr);
2401 }
2402
2403 static void
2404 do_store_static_field (VerifyContext *ctx, int token) {
2405         MonoClassField *field;
2406         MonoClass *klass;
2407         ILStackDesc *value;
2408
2409         if (!check_underflow (ctx, 1))
2410                 return;
2411
2412         value = stack_pop (ctx);
2413
2414         field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context);
2415         if (!field) {
2416                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store field from token 0x%08x at 0x%04x", token, ctx->ip_offset));
2417                 return;
2418         }
2419
2420         if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) { 
2421                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store non static field at 0x%04x", ctx->ip_offset));
2422                 return;
2423         }
2424
2425         if (field->type->type == MONO_TYPE_TYPEDBYREF) {
2426                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type in store static field at 0x%04x", ctx->ip_offset));
2427                 return;
2428         }
2429
2430         if (!mono_method_can_access_field (ctx->method, field))
2431                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset));
2432
2433         if (!verify_stack_type_compatibility (ctx, field->type, value))
2434                 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));   
2435 }
2436
2437 static gboolean
2438 check_is_valid_type_for_field_ops (VerifyContext *ctx, int token, ILStackDesc *obj, MonoClassField **ret_field)
2439 {
2440         MonoClassField *field;
2441         MonoClass *klass;
2442
2443         /*must be one of: object type, managed pointer, unmanaged pointer (native int) or an instance of a value type */
2444         if (!((obj->stype == TYPE_COMPLEX)
2445                 /* the managed reference must be to an object or value type */
2446                 || (( IS_MANAGED_POINTER (obj->stype)) && (UNMASK_TYPE (obj->stype) == TYPE_COMPLEX))
2447                 || (obj->stype == TYPE_NATIVE_INT)
2448                 || (obj->stype == TYPE_PTR)
2449                 || (obj->stype == TYPE_COMPLEX))) {
2450                 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));
2451         }
2452
2453         field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context);
2454         if (!field) {
2455                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ctx->ip_offset));
2456                 return FALSE;
2457         }
2458
2459         *ret_field = field;
2460
2461         if (field->type->type == MONO_TYPE_TYPEDBYREF) {
2462                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type at 0x%04x", ctx->ip_offset));
2463                 return FALSE;
2464         }
2465         g_assert (obj->type);
2466
2467         /*The value on the stack must be a subclass of the defining type of the field*/ 
2468         /* we need to check if we can load the field from the stack value*/
2469         if (UNMASK_TYPE (obj->stype) == TYPE_COMPLEX) {
2470                 MonoType *type = obj->type->byref ? &field->parent->this_arg : &field->parent->byval_arg;
2471
2472                 if (!verify_type_compatibility (ctx, type, obj->type)) {
2473                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not compatible to reference the field at 0x%04x", ctx->ip_offset));
2474                 }
2475
2476                 if (!mono_method_can_access_field (ctx->method, field))
2477                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset));
2478         }
2479
2480         if (!mono_method_can_access_field (ctx->method, field))
2481                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset));
2482
2483         if (obj->stype == TYPE_NATIVE_INT)
2484                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Native int is not a verifiable type to reference a field at 0x%04x", ctx->ip_offset));
2485
2486         check_unmanaged_pointer (ctx, obj);
2487         return TRUE;
2488 }
2489
2490 static void
2491 do_push_field (VerifyContext *ctx, int token, gboolean take_addr)
2492 {
2493         ILStackDesc *obj;
2494         MonoClassField *field;
2495
2496         if (!check_underflow (ctx, 1))
2497                 return;
2498         obj = stack_pop (ctx);
2499
2500         if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field))
2501                 return;
2502
2503         if (take_addr && field->parent->valuetype && !IS_MANAGED_POINTER (obj->stype))
2504                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a temporary value-type at 0x%04x", ctx->ip_offset));
2505
2506         if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
2507                 !(field->parent == ctx->method->klass && (ctx->method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && !strcmp (".ctor", ctx->method->name)))
2508                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
2509
2510         set_stack_value (stack_push (ctx), field->type, take_addr);
2511 }
2512
2513 static void
2514 do_store_field (VerifyContext *ctx, int token)
2515 {
2516         ILStackDesc *value, *obj;
2517         MonoClassField *field;
2518
2519         if (!check_underflow (ctx, 2))
2520                 return;
2521
2522         value = stack_pop (ctx);
2523         obj = stack_pop (ctx);
2524
2525         if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field))
2526                 return;
2527
2528         if (!verify_stack_type_compatibility (ctx, field->type, value))
2529                 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));  
2530 }
2531
2532 /*TODO proper handle for Nullable<T>*/
2533 static void
2534 do_box_value (VerifyContext *ctx, int klass_token)
2535 {
2536         ILStackDesc *value;
2537         MonoType *type = get_boxable_mono_type (ctx, klass_token);
2538
2539         if (!type)
2540                 return;
2541
2542         if (!check_underflow (ctx, 1))
2543                 return;
2544
2545         value = stack_top (ctx);
2546         /*box is a nop for reference types*/
2547         if (value->stype == TYPE_COMPLEX && MONO_TYPE_IS_REFERENCE (value->type) && MONO_TYPE_IS_REFERENCE (type))
2548                 return;
2549
2550         value = stack_pop (ctx);
2551
2552         if (!verify_stack_type_compatibility (ctx, type, value))
2553                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for boxing operation at 0x%04x", ctx->ip_offset));
2554
2555         stack_push_val (ctx, TYPE_COMPLEX, mono_class_get_type (mono_defaults.object_class));
2556 }
2557
2558 static void
2559 do_unbox_value (VerifyContext *ctx, int klass_token)
2560 {
2561         ILStackDesc *value;
2562         MonoType *type = get_boxable_mono_type (ctx, klass_token);
2563
2564         if (!type)
2565                 return;
2566  
2567         if (!check_underflow (ctx, 1))
2568                 return;
2569
2570         value = stack_pop (ctx);
2571
2572         if (value->stype != TYPE_COMPLEX || value->type->type != MONO_TYPE_OBJECT)
2573                 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));
2574
2575         //TODO Pushed managed pointer is haver controled mutability (CMMP) 
2576         set_stack_value (stack_push (ctx), mono_type_get_type_byref (type), FALSE);
2577 }
2578
2579 static void
2580 do_unary_math_op (VerifyContext *ctx, int op)
2581 {
2582         ILStackDesc *value;
2583         if (!check_underflow (ctx, 1))
2584                 return;
2585         value = stack_top (ctx);
2586         switch(value->stype) {
2587         case TYPE_I4:
2588         case TYPE_I8:
2589         case TYPE_NATIVE_INT:
2590                 break;
2591         case TYPE_R8:
2592                 if (op == CEE_NEG)
2593                         break;
2594         case TYPE_COMPLEX: /*only enums are ok*/
2595                 if (value->type->type == MONO_TYPE_VALUETYPE && value->type->data.klass->enumtype)
2596                         break;
2597         default:
2598                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for unary not at 0x%04x", ctx->ip_offset));
2599         }
2600 }
2601
2602 static void
2603 do_conversion (VerifyContext *ctx, int kind) 
2604 {
2605         ILStackDesc *value;
2606         if (!check_underflow (ctx, 1))
2607                 return;
2608         value = stack_pop (ctx);
2609
2610         switch(value->stype) {
2611         case TYPE_I4:
2612         case TYPE_I8:
2613         case TYPE_NATIVE_INT:
2614         case TYPE_R8:
2615                 break;
2616         default:
2617                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for conversion operation at 0x%04x", ctx->ip_offset));
2618         }
2619
2620         switch (kind) {
2621         case TYPE_I4:
2622                 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
2623                 break;
2624         case TYPE_I8:
2625                 stack_push_val (ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
2626                 break;
2627         case TYPE_R8:
2628                 stack_push_val (ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
2629                 break;
2630         case TYPE_NATIVE_INT:
2631                 stack_push_val (ctx, TYPE_NATIVE_INT, &mono_defaults.int_class->byval_arg);
2632                 break;
2633         default:
2634                 g_error ("unknown type %02x in conversion", kind);
2635
2636         }
2637 }
2638
2639 static void
2640 do_load_token (VerifyContext *ctx, int token) 
2641 {
2642         gpointer handle;
2643         MonoClass *handle_class;
2644         if (!check_overflow (ctx))
2645                 return;
2646         handle = mono_ldtoken (ctx->image, token, &handle_class, ctx->generic_context);
2647         if (!handle) {
2648                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid token 0x%x for ldtoken at 0x%04x", token, ctx->ip_offset));
2649                 return;
2650         }
2651         stack_push_val (ctx, TYPE_COMPLEX, mono_class_get_type (handle_class));
2652 }
2653
2654 static void
2655 do_ldobj_value (VerifyContext *ctx, int token) 
2656 {
2657         ILStackDesc *value;
2658         MonoType *type = get_boxable_mono_type (ctx, token);
2659
2660         if (!type)
2661                 return;
2662
2663         if (!check_underflow (ctx, 1))
2664                 return;
2665
2666         value = stack_pop (ctx);
2667         if (!IS_MANAGED_POINTER (value->stype) 
2668                         && value->stype != TYPE_NATIVE_INT
2669                         && !(value->stype == TYPE_PTR && value->type->type != MONO_TYPE_FNPTR)) {
2670                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid argument %s to ldobj at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
2671                 return;
2672         }
2673
2674         if (value->stype == TYPE_NATIVE_INT)
2675                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Using native pointer to ldobj at 0x%04x", ctx->ip_offset));
2676
2677         /*We have a byval on the stack, but the comparison must be strict. */
2678         if (!verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (value->type), TRUE))
2679                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldojb operation at 0x%04x", ctx->ip_offset));
2680
2681         set_stack_value (stack_push (ctx), type, FALSE);
2682 }
2683
2684 #define CTOR_REQUIRED_FLAGS (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_PUBLIC)
2685 #define CTOR_INVALID_FLAGS (METHOD_ATTRIBUTE_STATIC)
2686 /* TODO implement delegate verification */
2687 static void
2688 do_newobj (VerifyContext *ctx, int token) 
2689 {
2690         ILStackDesc *value;
2691         int i;
2692         MonoMethodSignature *sig;
2693         MonoMethod *method = mono_get_method_full (ctx->image, token, NULL, ctx->generic_context);
2694         if (!method) {
2695                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Constructor 0x%08x not found at 0x%04x", token, ctx->ip_offset));
2696                 return;
2697         }
2698
2699         if ((method->flags & CTOR_REQUIRED_FLAGS) != CTOR_REQUIRED_FLAGS
2700                 || (method->flags & CTOR_INVALID_FLAGS) != 0
2701                 || strcmp (".ctor", method->name)) {
2702                 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method from token 0x%08x not a constructor at 0x%04x", token, ctx->ip_offset));
2703                 return;
2704         }
2705
2706         if (method->klass->flags & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE))
2707                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Trying to instantiate an abstract or interface type at 0x%04x", ctx->ip_offset));
2708
2709         sig = mono_method_signature (method);
2710         if (!check_underflow (ctx, sig->param_count))
2711                 return;
2712
2713         for (i = sig->param_count - 1; i >= 0; --i) {
2714                 VERIFIER_DEBUG ( printf ("verifying constructor argument %d\n", i); );
2715                 value = stack_pop (ctx);
2716                 if (!verify_stack_type_compatibility (ctx, sig->params [i], value))
2717                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible parameter value with function signature at 0x%04x", ctx->ip_offset));
2718         }
2719
2720         if (check_overflow (ctx))
2721                 set_stack_value (stack_push (ctx),  &method->klass->byval_arg, FALSE);
2722 }
2723
2724 static MonoType *
2725 get_indirect_op_mono_type (int opcode) {
2726         switch (opcode) {
2727         case CEE_LDIND_I1:
2728         case CEE_LDIND_U1:
2729         case CEE_STIND_I1:
2730                 return &mono_defaults.sbyte_class->byval_arg;
2731
2732         case CEE_LDIND_I2:
2733         case CEE_LDIND_U2:
2734         case CEE_STIND_I2:
2735                 return &mono_defaults.int16_class->byval_arg;
2736
2737         case CEE_LDIND_I4:
2738         case CEE_LDIND_U4:
2739         case CEE_STIND_I4:
2740                 return &mono_defaults.int32_class->byval_arg;
2741
2742         case CEE_LDIND_I8:
2743         case CEE_STIND_I8:
2744                 return &mono_defaults.int64_class->byval_arg;
2745
2746         case CEE_LDIND_R4:
2747         case CEE_STIND_R4:
2748                 return &mono_defaults.single_class->byval_arg;
2749
2750         case CEE_LDIND_R8:
2751         case CEE_STIND_R8:
2752                 return &mono_defaults.double_class->byval_arg;
2753
2754         case CEE_LDIND_I:
2755         case CEE_STIND_I:
2756                 return &mono_defaults.int_class->byval_arg;
2757
2758         case CEE_LDIND_REF:
2759         case CEE_STIND_REF:
2760                 return &mono_defaults.object_class->byval_arg;
2761
2762         default:
2763                 g_error ("unknown opcode %02x in get_indirect_op_mono_type ", opcode);
2764                 return NULL;
2765         }
2766 }
2767
2768 static void
2769 do_load_indirect (VerifyContext *ctx, int opcode)
2770 {
2771         ILStackDesc *value;
2772         if (!check_underflow (ctx, 1))
2773                 return;
2774         
2775         value = stack_pop (ctx);
2776         if (!IS_MANAGED_POINTER (value->stype)) {
2777                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Load indirect not using a manager pointer at 0x%04x", ctx->ip_offset));
2778                 set_stack_value (stack_push (ctx), get_indirect_op_mono_type (opcode), FALSE);
2779                 return;
2780         }
2781
2782         if (opcode == CEE_LDIND_REF) {
2783                 if (UNMASK_TYPE (value->stype) != TYPE_COMPLEX || mono_class_from_mono_type (value->type)->valuetype)
2784                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind_ref expected object byref operation at 0x%04x", ctx->ip_offset));
2785                 set_stack_value (stack_push (ctx), mono_type_get_type_byval (value->type), FALSE);
2786         } else {
2787                 if (!verify_type_compatibility_full (ctx, get_indirect_op_mono_type (opcode), mono_type_get_type_byval (value->type), TRUE))
2788                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
2789                 set_stack_value (stack_push (ctx), get_indirect_op_mono_type (opcode), FALSE);
2790         }
2791 }
2792
2793 static void
2794 do_store_indirect (VerifyContext *ctx, int opcode)
2795 {
2796         ILStackDesc *addr, *val;
2797         if (!check_underflow (ctx, 2))
2798                 return;
2799
2800         val = stack_pop (ctx);
2801         addr = stack_pop (ctx); 
2802
2803         check_unmanaged_pointer (ctx, addr);
2804
2805         if (!IS_MANAGED_POINTER (addr->stype) && addr->stype != TYPE_PTR) {
2806                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid non-pointer argument to stind at 0x%04x", ctx->ip_offset));
2807                 return;
2808         }
2809
2810         if (!verify_type_compatibility_full (ctx, get_indirect_op_mono_type (opcode), mono_type_get_type_byval (addr->type), TRUE))
2811                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid addr type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
2812
2813         if (!verify_type_compatibility_full (ctx, get_indirect_op_mono_type (opcode), mono_type_get_type_byval (val->type), FALSE))
2814                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid addr type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
2815 }
2816
2817 static void
2818 do_newarr (VerifyContext *ctx, int token) 
2819 {
2820         ILStackDesc *value;
2821         MonoType *type = get_boxable_mono_type (ctx, token);
2822
2823         if (!type)
2824                 return;
2825
2826         if (!check_underflow (ctx, 1))
2827                 return;
2828
2829         value = stack_pop (ctx);
2830         if (value->stype != TYPE_I4 && value->stype != TYPE_NATIVE_INT)
2831                 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));
2832
2833         set_stack_value (stack_push (ctx), mono_class_get_type (mono_array_class_get (mono_class_from_mono_type (type), 1)), FALSE);
2834 }
2835
2836 static void
2837 do_ldlen (VerifyContext *ctx)
2838 {
2839         ILStackDesc *value;
2840
2841         if (!check_underflow (ctx, 1))
2842                 return;
2843
2844         value = stack_pop (ctx);
2845
2846         if (value->stype != TYPE_COMPLEX || value->type->type != MONO_TYPE_SZARRAY)
2847                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type for ldlen at 0x%04x", ctx->ip_offset));
2848
2849         stack_push_val (ctx, TYPE_NATIVE_INT, &mono_defaults.int_class->byval_arg);     
2850 }
2851
2852 /*Merge the stacks and perform compat checks*/
2853 static void
2854 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, int start) 
2855 {
2856         int i;
2857
2858         if (to->flags == IL_CODE_FLAG_NOT_PROCESSED) 
2859                         stack_init (ctx, to);
2860
2861         if (start) {
2862                 if (to->flags == IL_CODE_FLAG_NOT_PROCESSED) 
2863                         from->size = 0;
2864                 else
2865                         stack_copy (&ctx->eval, to); 
2866                 goto end_verify;
2867         } else if (to->flags == IL_CODE_FLAG_NOT_PROCESSED) {
2868                 stack_copy (to, from);
2869                 goto end_verify;
2870         }
2871         VERIFIER_DEBUG ( printf ("performing stack merge %d x %d\n", from->size, to->size); );
2872
2873         if (from->size != to->size) {
2874                 VERIFIER_DEBUG ( printf ("different stack sizes %d x %d\n", from->size, to->size); );
2875                 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Could not merge stacks, different sizes (%d x %d)", from->size, to->size)); 
2876                 goto end_verify;
2877         }
2878
2879         for (i = 0; i < from->size; ++i) {
2880                 ILStackDesc *from_slot = from->stack + i;
2881                 ILStackDesc *to_slot = to->stack + i;
2882
2883                 if (!verify_type_compatibility (ctx, mono_type_from_stack_slot (to_slot), mono_type_from_stack_slot (from_slot))) {
2884                         CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Could not merge stacks, types not compatible at 0x%04x", ctx->ip_offset)); 
2885                         goto end_verify;
2886                 }
2887
2888                 /*TODO we need to choose the base class for merging reference types*/
2889                 copy_stack_value (to_slot, from_slot);
2890         }
2891
2892 end_verify:
2893         to->flags = IL_CODE_FLAG_SEEN;
2894 }
2895
2896
2897 /*
2898  * FIXME: need to distinguish between valid and verifiable.
2899  * Need to keep track of types on the stack.
2900  * Verify types for opcodes.
2901  */
2902 GSList*
2903 mono_method_verify (MonoMethod *method, int level)
2904 {
2905         const unsigned char *ip;
2906         const unsigned char *end;
2907         const unsigned char *target = NULL; /* branch target */
2908         int i, n, need_merge = 0, start = 0;
2909         guint token, ip_offset = 0, prefix = 0;
2910         MonoGenericContext *generic_context = NULL;
2911         MonoImage *image;
2912         VerifyContext ctx;
2913         VERIFIER_DEBUG ( printf ("Verify IL for method %s %s %s\n",  method->klass->name,  method->klass->name, method->name); );
2914
2915         if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
2916                         (method->flags & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT))) {
2917                 return NULL;
2918         }
2919
2920         memset (&ctx, 0, sizeof (VerifyContext));
2921
2922         ctx.signature = mono_method_signature (method);
2923         if (!ctx.signature) {
2924                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method signature"));
2925                 return ctx.list;
2926         }
2927         ctx.header = mono_method_get_header (method);
2928         if (!ctx.header) {
2929                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method header"));
2930                 return ctx.list;
2931         }
2932         ctx.method = method;
2933         ip = ctx.header->code;
2934         end = ip + ctx.header->code_size;
2935         ctx.image = image = method->klass->image;
2936
2937
2938         ctx.max_args = ctx.signature->param_count + ctx.signature->hasthis;
2939         ctx.max_stack = ctx.header->max_stack;
2940         ctx.verifiable = ctx.valid = 1;
2941
2942         ctx.code = g_new0 (ILCodeDesc, ctx.header->code_size);
2943         ctx.code_size = ctx.header->code_size;
2944
2945         memset(ctx.code, 0, sizeof (ILCodeDesc) * ctx.header->code_size);
2946
2947
2948         ctx.num_locals = ctx.header->num_locals;
2949         ctx.locals = ctx.header->locals;
2950
2951
2952         if (ctx.signature->hasthis) {
2953                 ctx.params = g_new0 (MonoType*, ctx.max_args);
2954                 ctx.params [0] = method->klass->valuetype ? &method->klass->this_arg : &method->klass->byval_arg;
2955                 memcpy (ctx.params + 1, ctx.signature->params, sizeof (MonoType *) * ctx.signature->param_count);
2956         } else {
2957                 ctx.params = ctx.signature->params;
2958         }
2959
2960         if (ctx.signature->is_inflated)
2961                 ctx.generic_context = generic_context = mono_method_get_context (method);
2962
2963         stack_init (&ctx, &ctx.eval);
2964
2965
2966         for (i = 0; i < ctx.header->num_clauses; ++i) {
2967                 MonoExceptionClause *clause = ctx.header->clauses + i;
2968                 /* catch blocks and filter have the exception on the stack. */
2969                 /* must check boundaries for handler_offset and handler_start < handler_start*/
2970                 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
2971                         ILCodeDesc *code = ctx.code + clause->handler_offset;
2972                         stack_init (&ctx, code);
2973                         code->stack [0].stype = TYPE_COMPLEX;
2974                         code->stack [0].type = &clause->data.catch_class->byval_arg;
2975                         code->size = 1;
2976                         code->flags = IL_CODE_FLAG_SEEN;
2977                 }
2978                 else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2979                         ILCodeDesc *code = ctx.code + clause->data.filter_offset;
2980                         stack_init (&ctx, code);
2981                         code->stack [0].stype = TYPE_COMPLEX;
2982                         code->stack [0].type = &mono_defaults.exception_class->byval_arg;
2983                         code->size = 1;
2984                         code->flags = IL_CODE_FLAG_SEEN;
2985                 }
2986         }
2987
2988         while (ip < end && ctx.valid) {
2989                 ctx.ip_offset = ip_offset = ip - ctx.header->code;
2990
2991                 /*TODO id stack merge fails, we break, should't we - or only on errors??
2992                 TODO verify need_merge
2993                 */
2994                 if (need_merge) {
2995                         VERIFIER_DEBUG ( printf ("extra merge needed! %d \n", ctx.target); );
2996                         merge_stacks (&ctx, &ctx.eval, &ctx.code [ctx.target], FALSE);
2997                         need_merge = 0; 
2998                 }
2999                 merge_stacks (&ctx, &ctx.eval, &ctx.code[ip_offset], start);
3000                 start = 0;
3001
3002 #ifdef MONO_VERIFIER_DEBUG
3003                 {
3004                         char *discode;
3005                         discode = mono_disasm_code_one (NULL, method, ip, NULL);
3006                         discode [strlen (discode) - 1] = 0; /* no \n */
3007                         g_print ("[%d] %-29s (%d)\n",  ip_offset, discode, ctx.eval.size);
3008                         g_free (discode);
3009                 }
3010                 dump_stack_state (&ctx.code [ip_offset]);
3011 #endif
3012
3013                 switch (*ip) {
3014                 case CEE_NOP:
3015                 case CEE_BREAK:
3016                         ++ip;
3017                         break;
3018
3019                 case CEE_LDARG_0:
3020                 case CEE_LDARG_1:
3021                 case CEE_LDARG_2:
3022                 case CEE_LDARG_3:
3023                         push_arg (&ctx, *ip - CEE_LDARG_0, FALSE);
3024                         ++ip;
3025                         break;
3026
3027                 case CEE_LDARG_S:
3028                 case CEE_LDARGA_S:
3029                         push_arg (&ctx, ip [1],  *ip == CEE_LDARGA_S);
3030                         ip += 2;
3031                         break;
3032
3033                 case CEE_ADD:
3034                         do_binop (&ctx, *ip, add_table);
3035                         ++ip;
3036                         break;
3037
3038                 case CEE_SUB:
3039                         do_binop (&ctx, *ip, sub_table);
3040                         ++ip;
3041                         break;
3042
3043                 case CEE_MUL:
3044                 case CEE_DIV:
3045                 case CEE_REM:
3046                         do_binop (&ctx, *ip, bin_op_table);
3047                         ++ip;
3048                         break;
3049
3050                 case CEE_AND:
3051                 case CEE_DIV_UN:
3052                 case CEE_OR:
3053                 case CEE_REM_UN:
3054                 case CEE_XOR:
3055                         do_binop (&ctx, *ip, int_bin_op_table);
3056                         ++ip;
3057                         break;
3058
3059                 case CEE_SHL:
3060                 case CEE_SHR:
3061                 case CEE_SHR_UN:
3062                         do_binop (&ctx, *ip, shift_op_table);
3063                         ++ip;
3064                         break;
3065
3066                 case CEE_POP:
3067                         if (!check_underflow (&ctx, 1))
3068                                 break;
3069                         stack_pop (&ctx);
3070                         ++ip;
3071                         break;
3072
3073                 case CEE_RET:
3074                         do_ret (&ctx);
3075                         ++ip;
3076                         start = 1;
3077                         break;
3078
3079                 case CEE_LDLOC_0:
3080                 case CEE_LDLOC_1:
3081                 case CEE_LDLOC_2:
3082                 case CEE_LDLOC_3:
3083                         /*TODO support definite assignment verification? */
3084                         push_local (&ctx, *ip - CEE_LDLOC_0, FALSE);
3085                         ++ip;
3086                         break;
3087
3088                 case CEE_STLOC_0:
3089                 case CEE_STLOC_1:
3090                 case CEE_STLOC_2:
3091                 case CEE_STLOC_3:
3092                         store_local (&ctx, *ip - CEE_STLOC_0);
3093                         ++ip;
3094                         break;
3095
3096                 case CEE_STLOC_S:
3097                         store_local (&ctx, ip [1]);
3098                         ip += 2;
3099                         break;
3100
3101                 case CEE_STARG_S:
3102                         store_arg (&ctx, ip [1]);
3103                         ip += 2;
3104                         break;
3105
3106                 case CEE_LDC_I4_M1:
3107                 case CEE_LDC_I4_0:
3108                 case CEE_LDC_I4_1:
3109                 case CEE_LDC_I4_2:
3110                 case CEE_LDC_I4_3:
3111                 case CEE_LDC_I4_4:
3112                 case CEE_LDC_I4_5:
3113                 case CEE_LDC_I4_6:
3114                 case CEE_LDC_I4_7:
3115                 case CEE_LDC_I4_8:
3116                         if (check_overflow (&ctx))
3117                                 stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3118                         ++ip;
3119                         break;
3120
3121                 case CEE_LDC_I4_S:
3122                         if (check_overflow (&ctx))
3123                                 stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3124                         ip += 2;
3125                         break;
3126
3127                 case CEE_LDC_I4:
3128                         if (check_overflow (&ctx))
3129                                 stack_push_val (&ctx,TYPE_I4, &mono_defaults.int32_class->byval_arg);
3130                         ip += 5;
3131                         break;
3132
3133                 case CEE_LDC_I8:
3134                         if (check_overflow (&ctx))
3135                                 stack_push_val (&ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
3136                         ip += 9;
3137                         break;
3138
3139                 case CEE_LDC_R4:
3140                         if (check_overflow (&ctx))
3141                                 stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
3142                         ip += 5;
3143                         break;
3144
3145                 case CEE_LDC_R8:
3146                         if (check_overflow (&ctx))
3147                                 stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
3148                         ip += 9;
3149                         break;
3150
3151                 case CEE_LDNULL:
3152                         if (check_overflow (&ctx))
3153                                 stack_push_val (&ctx,TYPE_COMPLEX, &mono_defaults.object_class->byval_arg);
3154                         ++ip;
3155                         break;
3156
3157                 case CEE_BEQ_S:
3158                 case CEE_BNE_UN_S:
3159                         do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_eq_op);
3160                         ip += 2;
3161                         need_merge = 1;
3162                         break;
3163
3164                 case CEE_BGE_S:
3165                 case CEE_BGT_S:
3166                 case CEE_BLE_S:
3167                 case CEE_BLT_S:
3168                 case CEE_BGE_UN_S:
3169                 case CEE_BGT_UN_S:
3170                 case CEE_BLE_UN_S:
3171                 case CEE_BLT_UN_S:
3172                         do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_op);
3173                         ip += 2;
3174                         need_merge = 1;
3175                         break;
3176
3177                 case CEE_BEQ:
3178                 case CEE_BNE_UN:
3179                         do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_eq_op);
3180                         ip += 5;
3181                         need_merge = 1;
3182                         break;
3183
3184                 case CEE_BGE:
3185                 case CEE_BGT:
3186                 case CEE_BLE:
3187                 case CEE_BLT:
3188                 case CEE_BGE_UN:
3189                 case CEE_BGT_UN:
3190                 case CEE_BLE_UN:
3191                 case CEE_BLT_UN:
3192                         do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_op);
3193                         ip += 5;
3194                         need_merge = 1;
3195                         break;
3196
3197                 case CEE_LDLOC_S:
3198                 case CEE_LDLOCA_S:
3199                         push_local (&ctx, ip[1], *ip == CEE_LDLOCA_S);
3200                         ip += 2;
3201                         break;
3202
3203                 /* FIXME: warn/error instead? */
3204                 case CEE_UNUSED99:
3205                         ++ip;
3206                         break; 
3207
3208                 case CEE_DUP: {
3209                         ILStackDesc * top;
3210                         if (!check_underflow (&ctx, 1))
3211                                 break;
3212                         if (!check_overflow (&ctx))
3213                                 break;
3214                         top = stack_push (&ctx);
3215                         copy_stack_value (top, stack_get (&ctx, 1)); 
3216                         ++ip;
3217                         break;
3218                 }
3219
3220                 case CEE_JMP:
3221                         if (ctx.eval.size)
3222                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Eval stack must be empty in jmp at 0x%04x", ip_offset));
3223                         token = read32 (ip + 1);
3224                         if (in_any_block (ctx.header, ip_offset))
3225                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("jmp cannot escape exception blocks at 0x%04x", ip_offset));
3226                         /*
3227                          * FIXME: check signature, retval, arguments etc.
3228                          */
3229                         ip += 5;
3230                         break;
3231                 case CEE_CALL:
3232                 case CEE_CALLVIRT:
3233                         do_invoke_method (&ctx, read32 (ip + 1));
3234                         ip += 5;
3235                         break;
3236
3237                 case CEE_CALLI:
3238                         token = read32 (ip + 1);
3239                         /*
3240                          * FIXME: check signature, retval, arguments etc.
3241                          */
3242                         ip += 5;
3243                         break;
3244                 case CEE_BR_S:
3245                         target = ip + (signed char)ip [1] + 2;
3246                         if (target >= end || target < ctx.header->code)
3247                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
3248                         if (!in_same_block (ctx.header, ip_offset, target - ctx.header->code))
3249                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
3250                         ip += 2;
3251                         start = 1;
3252                         break;
3253
3254                 case CEE_BRFALSE_S:
3255                 case CEE_BRTRUE_S:
3256                         do_boolean_branch_op (&ctx, (signed char)ip [1] + 2);
3257                         ip += 2;
3258                         need_merge = 1;
3259                         break;
3260
3261                 case CEE_BR:
3262                         target = ip + (gint32)read32 (ip + 1) + 5;
3263                         if (target >= end || target < ctx.header->code)
3264                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
3265                         if (!in_same_block (ctx.header, ip_offset, target - ctx.header->code))
3266                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
3267                         ip += 5;
3268                         start = 1;
3269                         break;
3270
3271                 case CEE_BRFALSE:
3272                 case CEE_BRTRUE:
3273                         do_boolean_branch_op (&ctx, (gint32)read32 (ip + 1) + 5);
3274                         ip += 5;
3275                         need_merge = 1;
3276                         break;
3277
3278                 case CEE_SWITCH:
3279                         n = read32 (ip + 1);
3280                         target = ip + sizeof (guint32) * n;
3281                         /* FIXME: check that ip is in range (and within the same exception block) */
3282                         for (i = 0; i < n; ++i)
3283                                 if (target + (gint32) read32 (ip + 5 + i * sizeof (gint32)) >= end || target + (gint32) read32 (ip + 5 + i * sizeof (gint32)) < ctx.header->code)
3284                                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
3285                         if (!check_underflow (&ctx, 1))
3286                                 break;
3287                         if (stack_pop (&ctx)->stype != TYPE_I4)
3288                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid argument to switch at 0x%04x", ip_offset));
3289                         ip += 5 + sizeof (guint32) * n;
3290                         break;
3291
3292                 case CEE_LDIND_I1:
3293                 case CEE_LDIND_U1:
3294                 case CEE_LDIND_I2:
3295                 case CEE_LDIND_U2:
3296                 case CEE_LDIND_I4:
3297                 case CEE_LDIND_U4:
3298                 case CEE_LDIND_I8:
3299                 case CEE_LDIND_I:
3300                 case CEE_LDIND_R4:
3301                 case CEE_LDIND_R8:
3302                 case CEE_LDIND_REF:
3303                         do_load_indirect (&ctx, *ip);
3304                         ++ip;
3305                         break;
3306                         
3307                 case CEE_STIND_REF:
3308                 case CEE_STIND_I1:
3309                 case CEE_STIND_I2:
3310                 case CEE_STIND_I4:
3311                 case CEE_STIND_I8:
3312                 case CEE_STIND_R4:
3313                 case CEE_STIND_R8:
3314                 case CEE_STIND_I:
3315                         do_store_indirect (&ctx, *ip);
3316                         ++ip;
3317                         break;
3318
3319                 case CEE_NOT:
3320                 case CEE_NEG:
3321                         do_unary_math_op (&ctx, *ip);
3322                         ++ip;
3323                         break;
3324
3325                 //TODO: implement proper typecheck
3326                 case CEE_CONV_I1:
3327                 case CEE_CONV_I2:
3328                 case CEE_CONV_I4:
3329                 case CEE_CONV_U1:
3330                 case CEE_CONV_U2:
3331                 case CEE_CONV_U4:
3332                         do_conversion (&ctx, TYPE_I4);
3333                         ++ip;
3334                         break;                  
3335
3336                 case CEE_CONV_I8:
3337                 case CEE_CONV_U8:
3338                         do_conversion (&ctx, TYPE_I8);
3339                         ++ip;
3340                         break;                  
3341
3342                 case CEE_CONV_R4:
3343                 case CEE_CONV_R8:
3344                 case CEE_CONV_R_UN:
3345                         do_conversion (&ctx, TYPE_R8);
3346                         ++ip;
3347                         break;                  
3348
3349                 case CEE_CONV_I:
3350                 case CEE_CONV_U:
3351                         do_conversion (&ctx, TYPE_NATIVE_INT);
3352                         ++ip;
3353                         break;
3354
3355                 case CEE_CPOBJ:
3356                         token = read32 (ip + 1);
3357                         if (!check_underflow (&ctx, 2))
3358                                 break;
3359                         ctx.eval.size -= 2;
3360                         ip += 5;
3361                         break;
3362
3363                 case CEE_LDOBJ:
3364                         do_ldobj_value (&ctx, read32 (ip + 1));
3365                         ip += 5;
3366                         break;
3367
3368                 case CEE_LDSTR:
3369                         /*TODO verify if token is a valid string literal*/
3370                         token = read32 (ip + 1);
3371                         if (check_overflow (&ctx))
3372                                 stack_push_val (&ctx, TYPE_COMPLEX,  &mono_defaults.string_class->byval_arg);
3373                         ip += 5;
3374                         break;
3375
3376                 case CEE_NEWOBJ:
3377                         do_newobj (&ctx, read32 (ip + 1));
3378                         ip += 5;
3379                         break;
3380
3381                 case CEE_CASTCLASS:
3382                 case CEE_ISINST:
3383                         token = read32 (ip + 1);
3384                         if (!check_underflow (&ctx, 1))
3385                                 break;
3386                         ip += 5;
3387                         break;
3388                 case CEE_UNUSED58:
3389                 case CEE_UNUSED1:
3390                         ++ip; /* warn, error ? */
3391                         break;
3392                 case CEE_UNBOX:
3393                         do_unbox_value (&ctx, read32 (ip + 1));
3394                         ip += 5;
3395                         break;
3396                 case CEE_THROW:
3397                         if (!check_underflow (&ctx, 1))
3398                                 break;
3399                         stack_pop (&ctx);
3400                         ++ip;
3401                         start = 1;
3402                         break;
3403
3404                 case CEE_LDFLD:
3405                 case CEE_LDFLDA:
3406                         do_push_field (&ctx, read32 (ip + 1), *ip == CEE_LDFLDA);
3407                         ip += 5;
3408                         break;
3409
3410                 case CEE_LDSFLD:
3411                 case CEE_LDSFLDA:
3412                         do_push_static_field (&ctx, read32 (ip + 1), *ip == CEE_LDSFLDA);
3413                         ip += 5;
3414                         break;
3415
3416                 case CEE_STFLD:
3417                         do_store_field (&ctx, read32 (ip + 1));
3418                         ip += 5;
3419                         break;
3420
3421                 case CEE_STSFLD:
3422                         do_store_static_field (&ctx, read32 (ip + 1));
3423                         ip += 5;
3424                         break;
3425                 case CEE_STOBJ:
3426                         if (!check_underflow (&ctx, 2))
3427                                 break;
3428                         ctx.eval.size -= 2;
3429                         token = read32 (ip + 1);
3430                         ip += 5;
3431                         break;
3432
3433                 case CEE_CONV_OVF_I1_UN:
3434                 case CEE_CONV_OVF_I2_UN:
3435                 case CEE_CONV_OVF_I4_UN:
3436                 case CEE_CONV_OVF_U1_UN:
3437                 case CEE_CONV_OVF_U2_UN:
3438                 case CEE_CONV_OVF_U4_UN:
3439                         do_conversion (&ctx, TYPE_I4);
3440                         ++ip;
3441                         break;                  
3442
3443                 case CEE_CONV_OVF_I8_UN:
3444                 case CEE_CONV_OVF_U8_UN:
3445                         do_conversion (&ctx, TYPE_I8);
3446                         ++ip;
3447                         break;                  
3448
3449                 case CEE_CONV_OVF_I_UN:
3450                 case CEE_CONV_OVF_U_UN:
3451                         do_conversion (&ctx, TYPE_NATIVE_INT);
3452                         ++ip;
3453                         break;
3454
3455                 case CEE_BOX:
3456                         do_box_value (&ctx, read32 (ip + 1));
3457                         ip += 5;
3458                         break;
3459
3460                 case CEE_NEWARR:
3461                         do_newarr (&ctx, read32 (ip + 1));
3462                         ip += 5;
3463                         break;
3464
3465                 case CEE_LDLEN:
3466                         do_ldlen (&ctx);
3467                         ++ip;
3468                         break;
3469
3470                 case CEE_LDELEMA:
3471                         if (check_underflow (&ctx, 2))
3472                                 break;
3473                         --ctx.eval.size;
3474                         if (stack_top (&ctx)->stype != TYPE_COMPLEX)
3475                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid array argument to ldelema at 0x%04x", ip_offset));
3476                         if (stack_top (&ctx)->stype != TYPE_I4 && stack_top (&ctx)->stype != TYPE_PTR)
3477                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Array index needs to be Int32 or IntPtr at 0x%04x", ip_offset));
3478                         stack_top (&ctx)->stype = TYPE_COMPLEX;
3479                         token = read32 (ip + 1);
3480                         ip += 5;
3481                         break;
3482                 case CEE_LDELEM_I1:
3483                 case CEE_LDELEM_U1:
3484                 case CEE_LDELEM_I2:
3485                 case CEE_LDELEM_U2:
3486                 case CEE_LDELEM_I4:
3487                 case CEE_LDELEM_U4:
3488                 case CEE_LDELEM_I8:
3489                 case CEE_LDELEM_I:
3490                 case CEE_LDELEM_R4:
3491                 case CEE_LDELEM_R8:
3492                 case CEE_LDELEM_REF:
3493                         if (!check_underflow (&ctx, 2))
3494                                 break;
3495                         --ctx.eval.size;
3496                         if (stack_top (&ctx)->stype != TYPE_COMPLEX)
3497                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid array argument to ldelem at 0x%04x", ip_offset));
3498                         if (stack_top (&ctx)->stype != TYPE_I4 && stack_top (&ctx)->stype != TYPE_PTR)
3499                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Array index needs to be Int32 or IntPtr at 0x%04x", ip_offset));
3500                         stack_top (&ctx)->stype = ldelem_type [*ip - CEE_LDELEM_I1];
3501                         ++ip;
3502                         break;
3503                 case CEE_STELEM_I:
3504                 case CEE_STELEM_I1:
3505                 case CEE_STELEM_I2:
3506                 case CEE_STELEM_I4:
3507                 case CEE_STELEM_I8:
3508                 case CEE_STELEM_R4:
3509                 case CEE_STELEM_R8:
3510                 case CEE_STELEM_REF:
3511                         if (!check_underflow (&ctx, 3))
3512                                 break;
3513                         ctx.eval.size -= 3;
3514                         ++ip;
3515                         break;
3516                 case CEE_LDELEM_ANY:
3517                 case CEE_STELEM_ANY:
3518                 case CEE_UNBOX_ANY:
3519                 case CEE_UNUSED5:
3520                 case CEE_UNUSED6:
3521                 case CEE_UNUSED7:
3522                 case CEE_UNUSED8:
3523                 case CEE_UNUSED9:
3524                 case CEE_UNUSED10:
3525                 case CEE_UNUSED11:
3526                 case CEE_UNUSED12:
3527                 case CEE_UNUSED13:
3528                 case CEE_UNUSED14:
3529                 case CEE_UNUSED15:
3530                 case CEE_UNUSED16:
3531                 case CEE_UNUSED17:
3532                         ++ip; /* warn, error ? */
3533                         break;
3534
3535                 case CEE_CONV_OVF_I1:
3536                 case CEE_CONV_OVF_U1:
3537                 case CEE_CONV_OVF_I2:
3538                 case CEE_CONV_OVF_U2:
3539                 case CEE_CONV_OVF_I4:
3540                 case CEE_CONV_OVF_U4:
3541                         do_conversion (&ctx, TYPE_I4);
3542                         ++ip;
3543                         break;
3544
3545                 case CEE_CONV_OVF_I8:
3546                 case CEE_CONV_OVF_U8:
3547                         do_conversion (&ctx, TYPE_I8);
3548                         ++ip;
3549                         break;
3550
3551                 case CEE_CONV_OVF_I:
3552                 case CEE_CONV_OVF_U:
3553                         do_conversion (&ctx, TYPE_NATIVE_INT);
3554                         ++ip;
3555                         break;
3556
3557                 case CEE_UNUSED50:
3558                 case CEE_UNUSED18:
3559                 case CEE_UNUSED19:
3560                 case CEE_UNUSED20:
3561                 case CEE_UNUSED21:
3562                 case CEE_UNUSED22:
3563                 case CEE_UNUSED23:
3564                         ++ip; /* warn, error ? */
3565                         break;
3566                 case CEE_REFANYVAL:
3567                         if (!check_underflow (&ctx, 1))
3568                                 break;
3569                         ++ip;
3570                         break;
3571                 case CEE_CKFINITE:
3572                         if (!check_underflow (&ctx, 1))
3573                                 break;
3574                         ++ip;
3575                         break;
3576                 case CEE_UNUSED24:
3577                 case CEE_UNUSED25:
3578                         ++ip; /* warn, error ? */
3579                         break;
3580                 case CEE_MKREFANY:
3581                         if (!check_underflow (&ctx, 1))
3582                                 break;
3583                         token = read32 (ip + 1);
3584                         ip += 5;
3585                         break;
3586                 case CEE_UNUSED59:
3587                 case CEE_UNUSED60:
3588                 case CEE_UNUSED61:
3589                 case CEE_UNUSED62:
3590                 case CEE_UNUSED63:
3591                 case CEE_UNUSED64:
3592                 case CEE_UNUSED65:
3593                 case CEE_UNUSED66:
3594                 case CEE_UNUSED67:
3595                         ++ip; /* warn, error ? */
3596                         break;
3597                 case CEE_LDTOKEN:
3598                         do_load_token (&ctx, read32 (ip + 1));
3599                         ip += 5;
3600                         break;
3601
3602                 case CEE_ADD_OVF:
3603                 case CEE_ADD_OVF_UN:
3604                 case CEE_MUL_OVF:
3605                 case CEE_MUL_OVF_UN:
3606                 case CEE_SUB_OVF:
3607                 case CEE_SUB_OVF_UN:
3608                         if (!check_underflow (&ctx, 2))
3609                                 break;
3610                         stack_pop (&ctx);
3611                         ++ip;
3612                         break;
3613                 case CEE_ENDFINALLY:
3614                         ++ip;
3615                         start = 1;
3616                         break;
3617                 case CEE_LEAVE:
3618                         target = ip + (gint32)read32(ip + 1) + 5;
3619                         if (target >= end || target < ctx.header->code)
3620                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
3621                         if (!is_correct_leave (ctx.header, ip_offset, target - ctx.header->code))
3622                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ip_offset));
3623                         ip += 5;
3624                         start = 1;
3625                         break;
3626                 case CEE_LEAVE_S:
3627                         target = ip + (signed char)ip [1] + 2;
3628                         if (target >= end || target < ctx.header->code)
3629                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
3630                         if (!is_correct_leave (ctx.header, ip_offset, target - ctx.header->code))
3631                                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ip_offset));
3632                         ip += 2;
3633                         start = 1;
3634                         break;
3635                 case CEE_UNUSED26:
3636                 case CEE_UNUSED27:
3637                 case CEE_UNUSED28:
3638                 case CEE_UNUSED29:
3639                 case CEE_UNUSED30:
3640                 case CEE_UNUSED31:
3641                 case CEE_UNUSED32:
3642                 case CEE_UNUSED33:
3643                 case CEE_UNUSED34:
3644                 case CEE_UNUSED35:
3645                 case CEE_UNUSED36:
3646                 case CEE_UNUSED37:
3647                 case CEE_UNUSED38:
3648                 case CEE_UNUSED39:
3649                 case CEE_UNUSED40:
3650                 case CEE_UNUSED41:
3651                 case CEE_UNUSED42:
3652                 case CEE_UNUSED43:
3653                 case CEE_UNUSED44:
3654                 case CEE_UNUSED45:
3655                 case CEE_UNUSED46:
3656                 case CEE_UNUSED47:
3657                 case CEE_UNUSED48:
3658                         ++ip;
3659                         break;
3660                 case CEE_PREFIX7:
3661                 case CEE_PREFIX6:
3662                 case CEE_PREFIX5:
3663                 case CEE_PREFIX4:
3664                 case CEE_PREFIX3:
3665                 case CEE_PREFIX2:
3666                 case CEE_PREFIXREF:
3667                         ++ip;
3668                         break;
3669                 case CEE_PREFIX1:
3670                         ++ip;
3671                         switch (*ip) {
3672                         case CEE_STLOC:
3673                                 store_local (&ctx, read16 (ip + 1));
3674                                 ip += 3;
3675                                 break;
3676
3677                         case CEE_CEQ:
3678                                 do_cmp_op (&ctx, cmp_br_eq_op);
3679                                 ++ip;
3680                                 break;
3681
3682                         case CEE_CGT:
3683                         case CEE_CGT_UN:
3684                         case CEE_CLT:
3685                         case CEE_CLT_UN:
3686                                 do_cmp_op (&ctx, cmp_br_op);
3687                                 ++ip;
3688                                 break;
3689
3690                         case CEE_STARG:
3691                                 store_arg (&ctx, read16 (ip + 1) );
3692                                 ip += 3;
3693                                 break;
3694
3695
3696                         case CEE_ARGLIST:
3697                                 check_overflow (&ctx);
3698                                 ++ip;
3699                         case CEE_LDFTN:
3700                                 if (!check_overflow (&ctx))
3701                                         break;
3702                                 token = read32 (ip + 1);
3703                                 ip += 5;
3704                                 stack_top (&ctx)->stype = TYPE_PTR;
3705                                 ctx.eval.size++;
3706                                 break;
3707                         case CEE_LDVIRTFTN:
3708                                 if (!check_underflow (&ctx, 1))
3709                                         break;
3710                                 token = read32 (ip + 1);
3711                                 ip += 5;
3712                                 if (stack_top (&ctx)->stype != TYPE_COMPLEX)
3713                                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid argument to ldvirtftn at 0x%04x", ip_offset));
3714                                 stack_top (&ctx)->stype = TYPE_PTR;
3715                                 break;
3716                         case CEE_UNUSED56:
3717                                 ++ip;
3718                                 break;
3719
3720                         case CEE_LDARG:
3721                         case CEE_LDARGA:
3722                                 push_arg (&ctx, read16 (ip + 1),  *ip == CEE_LDARGA);
3723                                 ip += 3;
3724                                 break;
3725
3726                         case CEE_LDLOC:
3727                         case CEE_LDLOCA:
3728                                 push_local (&ctx, read16 (ip + 1), *ip == CEE_LDLOCA);
3729                                 ip += 3;
3730                                 break;
3731
3732                         case CEE_LOCALLOC:
3733                                 if (ctx.eval.size != 1)
3734                                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ip_offset));
3735                                 if (stack_top (&ctx)->stype != TYPE_I4 && stack_top (&ctx)->stype != TYPE_PTR)
3736                                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid argument to localloc at 0x%04x", ip_offset));
3737                                 stack_top (&ctx)->stype = TYPE_COMPLEX;
3738                                 ++ip;
3739                                 break;
3740                         case CEE_UNUSED57:
3741                                 ++ip;
3742                                 break;
3743                         case CEE_ENDFILTER:
3744                                 if (ctx.eval.size != 1)
3745                                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Stack must have only filter result in endfilter at 0x%04x", ip_offset));
3746                                 ++ip;
3747                                 break;
3748                         case CEE_UNALIGNED_:
3749                                 prefix |= PREFIX_UNALIGNED;
3750                                 ++ip;
3751                                 break;
3752                         case CEE_VOLATILE_:
3753                                 prefix |= PREFIX_VOLATILE;
3754                                 ++ip;
3755                                 break;
3756                         case CEE_TAIL_:
3757                                 prefix |= PREFIX_TAIL;
3758                                 ++ip;
3759                                 if (ip < end && (*ip != CEE_CALL && *ip != CEE_CALLI && *ip != CEE_CALLVIRT))
3760                                         ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("tail prefix must be used only with call opcodes at 0x%04x", ip_offset));
3761                                 break;
3762                         case CEE_INITOBJ:
3763                                 if (!check_underflow (&ctx, 1))
3764                                         break;
3765                                 token = read32 (ip + 1);
3766                                 ip += 5;
3767                                 stack_pop (&ctx);
3768                                 break;
3769                         case CEE_CONSTRAINED_:
3770                                 token = read32 (ip + 1);
3771                                 ip += 5;
3772                                 break;
3773                         case CEE_CPBLK:
3774                                 if (!check_underflow (&ctx, 3))
3775                                         break;
3776                                 ip++;
3777                                 break;
3778                         case CEE_INITBLK:
3779                                 if (!check_underflow (&ctx, 3))
3780                                         break;
3781                                 ip++;
3782                                 break;
3783                         case CEE_NO_:
3784                                 ip += 2;
3785                                 break;
3786                         case CEE_RETHROW:
3787                                 ++ip;
3788                                 break;
3789                         case CEE_UNUSED:
3790                                 ++ip;
3791                                 break;
3792                         case CEE_SIZEOF:
3793                                 if (!check_overflow (&ctx))
3794                                         break;
3795                                 token = read32 (ip + 1);
3796                                 ip += 5;
3797                                 stack_top (&ctx)->type = &mono_defaults.uint32_class->byval_arg;
3798                                 stack_top (&ctx)->stype = TYPE_I4;
3799                                 ctx.eval.size++;
3800                                 break;
3801                         case CEE_REFANYTYPE:
3802                                 if (!check_underflow (&ctx, 1))
3803                                         break;
3804                                 ++ip;
3805                                 break;
3806                         case CEE_UNUSED53:
3807                         case CEE_UNUSED54:
3808                         case CEE_UNUSED55:
3809                         case CEE_UNUSED70:
3810                                 ++ip;
3811                                 break;
3812                         }
3813                 }
3814         }
3815         /*
3816          * if ip != end we overflowed: mark as error.
3817          */
3818         if ((ip != end || !start) && ctx.verifiable && !ctx.list) {
3819                 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Run ahead of method code at 0x%04x", ip_offset));
3820         }
3821
3822 invalid_cil:
3823
3824         if (ctx.code) {
3825                 for (i = 0; i < ctx.header->code_size; ++i) {
3826                         if (ctx.code [i].stack)
3827                                 g_free (ctx.code [i].stack);
3828                 }
3829         }
3830
3831         if (ctx.eval.stack)
3832                 g_free (ctx.eval.stack);
3833         if (ctx.code)
3834                 g_free (ctx.code);
3835         if (ctx.signature->hasthis)
3836                 g_free (ctx.params);
3837
3838         return ctx.list;
3839 }
3840
3841 typedef struct {
3842         const char *name;
3843         guint64 offset;
3844 } FieldDesc;
3845
3846 typedef struct {
3847         const char *name;
3848         const FieldDesc *fields;
3849 } ClassDesc;
3850
3851 static const FieldDesc 
3852 typebuilder_fields[] = {
3853         {"tname", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, name)},
3854         {"nspace", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, nspace)},
3855         {"parent", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, parent)},
3856         {"interfaces", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, interfaces)},
3857         {"methods", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, methods)},
3858         {"properties", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, properties)},
3859         {"fields", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, fields)},
3860         {"attrs", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, attrs)},
3861         {"table_idx", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, table_idx)},
3862         {NULL, 0}
3863 };
3864
3865 static const FieldDesc 
3866 modulebuilder_fields[] = {
3867         {"types", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, types)},
3868         {"cattrs", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, cattrs)},
3869         {"guid", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, guid)},
3870         {"table_idx", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, table_idx)},
3871         {NULL, 0}
3872 };
3873
3874 static const FieldDesc 
3875 assemblybuilder_fields[] = {
3876         {"entry_point", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, entry_point)},
3877         {"modules", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, modules)},
3878         {"name", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, name)},
3879         {"resources", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, resources)},
3880         {"version", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, version)},
3881         {"culture", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, culture)},
3882         {NULL, 0}
3883 };
3884
3885 static const FieldDesc 
3886 ctorbuilder_fields[] = {
3887         {"ilgen", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, ilgen)},
3888         {"parameters", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, parameters)},
3889         {"attrs", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, attrs)},
3890         {"iattrs", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, iattrs)},
3891         {"table_idx", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, table_idx)},
3892         {"call_conv", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, call_conv)},
3893         {"type", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, type)},
3894         {NULL, 0}
3895 };
3896
3897 static const FieldDesc 
3898 methodbuilder_fields[] = {
3899         {"mhandle", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, mhandle)},
3900         {"rtype", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, rtype)},
3901         {"parameters", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, parameters)},
3902         {"attrs", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, attrs)},
3903         {"iattrs", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, iattrs)},
3904         {"name", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, name)},
3905         {"table_idx", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, table_idx)},
3906         {"code", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, code)},
3907         {"ilgen", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, ilgen)},
3908         {"type", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, type)},
3909         {"pinfo", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, pinfo)},
3910         {"pi_dll", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, dll)},
3911         {"pi_entry", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, dllentry)},
3912         {"charset", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, charset)},
3913         {"extra_flags", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, extra_flags)},
3914         {"native_cc", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, native_cc)},
3915         {"call_conv", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, call_conv)},
3916         {NULL, 0}
3917 };
3918
3919 static const FieldDesc 
3920 fieldbuilder_fields[] = {
3921         {"attrs", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, attrs)},
3922         {"type", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, type)},
3923         {"name", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, name)},
3924         {"def_value", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, def_value)},
3925         {"offset", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, offset)},
3926         {"table_idx", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, table_idx)},
3927         {NULL, 0}
3928 };
3929
3930 static const FieldDesc 
3931 propertybuilder_fields[] = {
3932         {"attrs", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, attrs)},
3933         {"name", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, name)},
3934         {"type", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, type)},
3935         {"parameters", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, parameters)},
3936         {"def_value", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, def_value)},
3937         {"set_method", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, set_method)},
3938         {"get_method", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, get_method)},
3939         {"table_idx", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, table_idx)},
3940         {NULL, 0}
3941 };
3942
3943 static const FieldDesc 
3944 ilgenerator_fields[] = {
3945         {"code", G_STRUCT_OFFSET (MonoReflectionILGen, code)},
3946         {"code_len", G_STRUCT_OFFSET (MonoReflectionILGen, code_len)},
3947         {"max_stack", G_STRUCT_OFFSET (MonoReflectionILGen, max_stack)},
3948         {"cur_stack", G_STRUCT_OFFSET (MonoReflectionILGen, cur_stack)},
3949         {"locals", G_STRUCT_OFFSET (MonoReflectionILGen, locals)},
3950         {"ex_handlers", G_STRUCT_OFFSET (MonoReflectionILGen, ex_handlers)},
3951         {NULL, 0}
3952 };
3953
3954 static const FieldDesc 
3955 ilexinfo_fields[] = {
3956         {"handlers", G_STRUCT_OFFSET (MonoILExceptionInfo, handlers)},
3957         {"start", G_STRUCT_OFFSET (MonoILExceptionInfo, start)},
3958         {"len", G_STRUCT_OFFSET (MonoILExceptionInfo, len)},
3959         {"end", G_STRUCT_OFFSET (MonoILExceptionInfo, label)},
3960         {NULL, 0}
3961 };
3962
3963 static const FieldDesc 
3964 ilexblock_fields[] = {
3965         {"extype", G_STRUCT_OFFSET (MonoILExceptionBlock, extype)},
3966         {"type", G_STRUCT_OFFSET (MonoILExceptionBlock, type)},
3967         {"start", G_STRUCT_OFFSET (MonoILExceptionBlock, start)},
3968         {"len", G_STRUCT_OFFSET (MonoILExceptionBlock, len)},
3969         {"filter_offset", G_STRUCT_OFFSET (MonoILExceptionBlock, filter_offset)},
3970         {NULL, 0}
3971 };
3972
3973 static const ClassDesc
3974 emit_classes_to_check [] = {
3975         {"TypeBuilder", typebuilder_fields},
3976         {"ModuleBuilder", modulebuilder_fields},
3977         {"AssemblyBuilder", assemblybuilder_fields},
3978         {"ConstructorBuilder", ctorbuilder_fields},
3979         {"MethodBuilder", methodbuilder_fields},
3980         {"FieldBuilder", fieldbuilder_fields},
3981         {"PropertyBuilder", propertybuilder_fields},
3982         {"ILGenerator", ilgenerator_fields},
3983         {"ILExceptionBlock", ilexblock_fields},
3984         {"ILExceptionInfo", ilexinfo_fields},
3985         {NULL, NULL}
3986 };
3987
3988 static const FieldDesc 
3989 monoevent_fields[] = {
3990         {"klass", G_STRUCT_OFFSET (MonoReflectionEvent, klass)},
3991         {"handle", G_STRUCT_OFFSET (MonoReflectionEvent, event)},
3992         {NULL, 0}
3993 };
3994
3995 static const FieldDesc 
3996 monoproperty_fields[] = {
3997         {"klass", G_STRUCT_OFFSET (MonoReflectionProperty, klass)},
3998         {"prop", G_STRUCT_OFFSET (MonoReflectionProperty, property)},
3999         {NULL, 0}
4000 };
4001
4002 static const FieldDesc 
4003 monofield_fields[] = {
4004         {"klass", G_STRUCT_OFFSET (MonoReflectionField, klass)},
4005         {"fhandle", G_STRUCT_OFFSET (MonoReflectionField, field)},
4006         {NULL, 0}
4007 };
4008
4009 static const FieldDesc 
4010 monomethodinfo_fields[] = {
4011         {"parent", G_STRUCT_OFFSET (MonoMethodInfo, parent)},
4012         {"ret", G_STRUCT_OFFSET (MonoMethodInfo, ret)},
4013         {"attrs", G_STRUCT_OFFSET (MonoMethodInfo, attrs)},
4014         {"iattrs", G_STRUCT_OFFSET (MonoMethodInfo, implattrs)},
4015         {NULL, 0}
4016 };
4017
4018 static const FieldDesc 
4019 monopropertyinfo_fields[] = {
4020         {"parent", G_STRUCT_OFFSET (MonoPropertyInfo, parent)},
4021         {"name", G_STRUCT_OFFSET (MonoPropertyInfo, name)},
4022         {"get_method", G_STRUCT_OFFSET (MonoPropertyInfo, get)},
4023         {"set_method", G_STRUCT_OFFSET (MonoPropertyInfo, set)},
4024         {"attrs", G_STRUCT_OFFSET (MonoPropertyInfo, attrs)},
4025         {NULL, 0}
4026 };
4027
4028 static const FieldDesc 
4029 monomethod_fields[] = {
4030         {"mhandle", G_STRUCT_OFFSET (MonoReflectionMethod, method)},
4031         {NULL, 0}
4032 };
4033
4034 static const FieldDesc 
4035 monocmethod_fields[] = {
4036         {"mhandle", G_STRUCT_OFFSET (MonoReflectionMethod, method)},
4037         {NULL, 0}
4038 };
4039
4040 static const FieldDesc 
4041 pinfo_fields[] = {
4042         {"ClassImpl", G_STRUCT_OFFSET (MonoReflectionParameter, ClassImpl)},
4043         {"DefaultValueImpl", G_STRUCT_OFFSET (MonoReflectionParameter, DefaultValueImpl)},
4044         {"MemberImpl", G_STRUCT_OFFSET (MonoReflectionParameter, MemberImpl)},
4045         {"NameImpl", G_STRUCT_OFFSET (MonoReflectionParameter, NameImpl)},
4046         {"PositionImpl", G_STRUCT_OFFSET (MonoReflectionParameter, PositionImpl)},
4047         {"AttrsImpl", G_STRUCT_OFFSET (MonoReflectionParameter, AttrsImpl)},
4048         {NULL, 0}
4049 };
4050
4051 static const ClassDesc
4052 reflection_classes_to_check [] = {
4053         {"MonoEvent", monoevent_fields},
4054         {"MonoProperty", monoproperty_fields},
4055         {"MonoField", monofield_fields},
4056         {"MonoMethodInfo", monomethodinfo_fields},
4057         {"MonoPropertyInfo", monopropertyinfo_fields},
4058         {"MonoMethod", monomethod_fields},
4059         {"MonoCMethod", monocmethod_fields},
4060         {"ParameterInfo", pinfo_fields},
4061         {NULL, NULL}
4062 };
4063
4064 static FieldDesc 
4065 enuminfo_fields[] = {
4066         {"utype", G_STRUCT_OFFSET (MonoEnumInfo, utype)},
4067         {"values", G_STRUCT_OFFSET (MonoEnumInfo, values)},
4068         {"names", G_STRUCT_OFFSET (MonoEnumInfo, names)},
4069         {NULL, 0}
4070 };
4071
4072 static FieldDesc 
4073 delegate_fields[] = {
4074         {"target_type", G_STRUCT_OFFSET (MonoDelegate, target_type)},
4075         {"m_target", G_STRUCT_OFFSET (MonoDelegate, target)},
4076         {"method_name", G_STRUCT_OFFSET (MonoDelegate, method_name)},
4077         {"method_ptr", G_STRUCT_OFFSET (MonoDelegate, method_ptr)},
4078         {"delegate_trampoline", G_STRUCT_OFFSET (MonoDelegate, delegate_trampoline)},
4079         {"method_info", G_STRUCT_OFFSET (MonoDelegate, method_info)},
4080         {NULL, 0}
4081 };
4082
4083 static FieldDesc 
4084 multicast_delegate_fields[] = {
4085         {"prev", G_STRUCT_OFFSET (MonoMulticastDelegate, prev)},
4086         {NULL, 0}
4087 };
4088
4089 static FieldDesc 
4090 async_result_fields[] = {
4091         {"async_state", G_STRUCT_OFFSET (MonoAsyncResult, async_state)},
4092         {"handle", G_STRUCT_OFFSET (MonoAsyncResult, handle)},
4093         {"async_delegate", G_STRUCT_OFFSET (MonoAsyncResult, async_delegate)},
4094         {"data", G_STRUCT_OFFSET (MonoAsyncResult, data)},
4095         {"sync_completed", G_STRUCT_OFFSET (MonoAsyncResult, sync_completed)},
4096         {"completed", G_STRUCT_OFFSET (MonoAsyncResult, completed)},
4097         {"endinvoke_called", G_STRUCT_OFFSET (MonoAsyncResult, endinvoke_called)},
4098         {"async_callback", G_STRUCT_OFFSET (MonoAsyncResult, async_callback)},
4099         {NULL, 0}
4100 };
4101
4102 static FieldDesc 
4103 exception_fields[] = {
4104         {"trace_ips", G_STRUCT_OFFSET (MonoException, trace_ips)},
4105         {"inner_exception", G_STRUCT_OFFSET (MonoException, inner_ex)},
4106         {"message", G_STRUCT_OFFSET (MonoException, message)},
4107         {"help_link", G_STRUCT_OFFSET (MonoException, help_link)},
4108         {"class_name", G_STRUCT_OFFSET (MonoException, class_name)},
4109         {"stack_trace", G_STRUCT_OFFSET (MonoException, stack_trace)},
4110         {"remote_stack_trace", G_STRUCT_OFFSET (MonoException, remote_stack_trace)},
4111         {"remote_stack_index", G_STRUCT_OFFSET (MonoException, remote_stack_index)},
4112         {"hresult", G_STRUCT_OFFSET (MonoException, hresult)},
4113         {"source", G_STRUCT_OFFSET (MonoException, source)},
4114         {NULL, 0}
4115 };
4116
4117 static const ClassDesc
4118 system_classes_to_check [] = {
4119         {"Exception", exception_fields},
4120         {"MonoEnumInfo", enuminfo_fields},
4121         {"Delegate", delegate_fields},
4122         {"MulticastDelegate", multicast_delegate_fields},
4123         {NULL, NULL}
4124 };
4125
4126 static FieldDesc 
4127 stack_frame_fields [] = {
4128         {"ilOffset", G_STRUCT_OFFSET (MonoStackFrame, il_offset)},
4129         {"nativeOffset", G_STRUCT_OFFSET (MonoStackFrame, native_offset)},
4130         {"methodBase", G_STRUCT_OFFSET (MonoStackFrame, method)},
4131         {"fileName", G_STRUCT_OFFSET (MonoStackFrame, filename)},
4132         {"lineNumber", G_STRUCT_OFFSET (MonoStackFrame, line)},
4133         {"columnNumber", G_STRUCT_OFFSET (MonoStackFrame, column)},
4134         {NULL, 0}
4135 };
4136
4137 static const ClassDesc
4138 system_diagnostics_classes_to_check [] = {
4139         {"StackFrame", stack_frame_fields},
4140         {NULL, NULL}
4141 };
4142
4143 static FieldDesc 
4144 mono_method_message_fields[] = {
4145         {"method", G_STRUCT_OFFSET (MonoMethodMessage, method)},
4146         {"args", G_STRUCT_OFFSET (MonoMethodMessage, args)},
4147         {"names", G_STRUCT_OFFSET (MonoMethodMessage, names)},
4148         {"arg_types", G_STRUCT_OFFSET (MonoMethodMessage, arg_types)},
4149         {"ctx", G_STRUCT_OFFSET (MonoMethodMessage, ctx)},
4150         {"rval", G_STRUCT_OFFSET (MonoMethodMessage, rval)},
4151         {"exc", G_STRUCT_OFFSET (MonoMethodMessage, exc)},
4152         {NULL, 0}
4153 };
4154
4155 static const ClassDesc
4156 messaging_classes_to_check [] = {
4157         {"AsyncResult", async_result_fields},
4158         {"MonoMethodMessage", mono_method_message_fields},
4159         {NULL, NULL}
4160 };
4161
4162 static FieldDesc 
4163 transparent_proxy_fields[] = {
4164         {"_rp", G_STRUCT_OFFSET (MonoTransparentProxy, rp)},
4165         {"_class", G_STRUCT_OFFSET (MonoTransparentProxy, remote_class)},
4166         {NULL, 0}
4167 };
4168
4169 static FieldDesc 
4170 real_proxy_fields[] = {
4171         {"class_to_proxy", G_STRUCT_OFFSET (MonoRealProxy, class_to_proxy)},
4172         {NULL, 0}
4173 };
4174
4175 static const ClassDesc
4176 proxy_classes_to_check [] = {
4177         {"TransparentProxy", transparent_proxy_fields},
4178         {"RealProxy", real_proxy_fields},
4179         {NULL, NULL}
4180 };
4181
4182 static FieldDesc 
4183 wait_handle_fields[] = {
4184         {"os_handle", G_STRUCT_OFFSET (MonoWaitHandle, handle)},
4185         {"disposed", G_STRUCT_OFFSET (MonoWaitHandle, disposed)},
4186         {NULL, 0}
4187 };
4188
4189 static FieldDesc 
4190 thread_fields[] = {
4191         {"system_thread_handle", G_STRUCT_OFFSET (MonoThread, handle)},
4192         {"threadpool_thread", G_STRUCT_OFFSET (MonoThread, threadpool_thread)},
4193         {"state", G_STRUCT_OFFSET (MonoThread, state)},
4194         {"abort_exc", G_STRUCT_OFFSET (MonoThread, abort_exc)},
4195         {"abort_state", G_STRUCT_OFFSET (MonoThread, abort_state)},
4196         {"thread_id", G_STRUCT_OFFSET (MonoThread, tid)},
4197         {NULL, 0}
4198 };
4199
4200 static const ClassDesc
4201 threading_classes_to_check [] = {
4202         {"Thread", thread_fields},
4203         {"WaitHandle", wait_handle_fields},
4204         {NULL, NULL}
4205 };
4206
4207 static const FieldDesc
4208 cinfo_fields[] = {
4209         {"datetime_format", G_STRUCT_OFFSET (MonoCultureInfo, datetime_format)},
4210         {"number_format", G_STRUCT_OFFSET (MonoCultureInfo, number_format)},
4211         {"textinfo", G_STRUCT_OFFSET (MonoCultureInfo, textinfo)},
4212         {"name", G_STRUCT_OFFSET (MonoCultureInfo, name)},
4213         {"displayname", G_STRUCT_OFFSET (MonoCultureInfo, displayname)},
4214         {"englishname", G_STRUCT_OFFSET (MonoCultureInfo, englishname)},
4215         {"nativename", G_STRUCT_OFFSET (MonoCultureInfo, nativename)},
4216         {"iso3lang", G_STRUCT_OFFSET (MonoCultureInfo, iso3lang)},
4217         {"iso2lang", G_STRUCT_OFFSET (MonoCultureInfo, iso2lang)},
4218         {"icu_name", G_STRUCT_OFFSET (MonoCultureInfo, icu_name)},
4219         {"win3lang", G_STRUCT_OFFSET (MonoCultureInfo, win3lang)},
4220         {"compareinfo", G_STRUCT_OFFSET (MonoCultureInfo, compareinfo)},
4221         {NULL, 0}
4222 };
4223
4224 static const FieldDesc
4225 dtfinfo_fields[] = {
4226         {"amDesignator", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, AMDesignator)},
4227         {"pmDesignator", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, PMDesignator)},
4228         {"dayNames", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, DayNames)},
4229         {"monthNames", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, MonthNames)},
4230         {NULL, 0}
4231 };
4232
4233 static const FieldDesc
4234 nfinfo_fields[] = {
4235         {"decimalFormats", G_STRUCT_OFFSET (MonoNumberFormatInfo, decimalFormats)},
4236         {"currencySymbol", G_STRUCT_OFFSET (MonoNumberFormatInfo, currencySymbol)},
4237         {"percentSymbol", G_STRUCT_OFFSET (MonoNumberFormatInfo, percentSymbol)},
4238         {"positiveSign", G_STRUCT_OFFSET (MonoNumberFormatInfo, positiveSign)},
4239         {NULL, 0}
4240 };
4241
4242 static const FieldDesc
4243 compinfo_fields[] = {
4244         {"lcid", G_STRUCT_OFFSET (MonoCompareInfo, lcid)},
4245         {"ICU_collator", G_STRUCT_OFFSET (MonoCompareInfo, ICU_collator)},
4246         {NULL, 0}
4247 };
4248
4249 static const FieldDesc
4250 sortkey_fields[] = {
4251         {"str", G_STRUCT_OFFSET (MonoSortKey, str)},
4252         {"options", G_STRUCT_OFFSET (MonoSortKey, options)},
4253         {"key", G_STRUCT_OFFSET (MonoSortKey, key)},
4254         {"lcid", G_STRUCT_OFFSET (MonoSortKey, lcid)},
4255         {NULL, 0}
4256 };
4257
4258 static const ClassDesc
4259 globalization_classes_to_check [] = {
4260         {"CultureInfo", cinfo_fields},
4261         {"DateTimeFormatInfo", dtfinfo_fields},
4262         {"NumberFormatInfo", nfinfo_fields},
4263         {"CompareInfo", compinfo_fields},
4264         {"SortKey", sortkey_fields},
4265         {NULL, NULL}
4266 };
4267
4268 static const FieldDesc
4269 safe_handle_fields[] ={
4270         {"handle", G_STRUCT_OFFSET (MonoSafeHandle, handle)},
4271         {NULL, 0}
4272 };
4273
4274 static const ClassDesc interop_classes_to_check [] = {
4275         {"SafeHandle", safe_handle_fields},
4276         {NULL, NULL}
4277 };
4278
4279 typedef struct {
4280         const char *name;
4281         const ClassDesc *types;
4282 } NameSpaceDesc;
4283
4284 static const NameSpaceDesc
4285 namespaces_to_check[] = {
4286         {"System.Runtime.Remoting.Proxies", proxy_classes_to_check},
4287         {"System.Runtime.Remoting.Messaging", messaging_classes_to_check},
4288         {"System.Reflection.Emit", emit_classes_to_check},
4289         {"System.Reflection", reflection_classes_to_check},
4290         {"System.Threading", threading_classes_to_check},
4291         {"System.Diagnostics", system_diagnostics_classes_to_check},
4292         {"System", system_classes_to_check},
4293         {"System.Globalization", globalization_classes_to_check},
4294         {"System.Runtime.InteropServices", interop_classes_to_check},
4295         {NULL, NULL}
4296 };
4297
4298 static char*
4299 check_corlib (MonoImage *corlib)
4300 {
4301         MonoClass *klass;
4302         MonoClassField *field;
4303         const FieldDesc *fdesc;
4304         const ClassDesc *cdesc;
4305         const NameSpaceDesc *ndesc;
4306         gint struct_offset;
4307         GString *result = NULL;
4308
4309         for (ndesc = namespaces_to_check; ndesc->name; ++ndesc) {
4310                 for (cdesc = ndesc->types; cdesc->name; ++cdesc) {
4311                         klass = mono_class_from_name (corlib, ndesc->name, cdesc->name);
4312                         if (!klass) {
4313                                 if (!result)
4314                                         result = g_string_new ("");
4315                                 g_string_append_printf (result, "Cannot find class %s\n", cdesc->name);
4316                                 continue;
4317                         }
4318                         mono_class_init (klass);
4319                         /*
4320                          * FIXME: we should also check the size of valuetypes, or
4321                          * we're going to have trouble when we access them in arrays.
4322                          */
4323                         if (klass->valuetype)
4324                                 struct_offset = sizeof (MonoObject);
4325                         else
4326                                 struct_offset = 0;
4327                         for (fdesc = cdesc->fields; fdesc->name; ++fdesc) {
4328                                 field = mono_class_get_field_from_name (klass, fdesc->name);
4329                                 if (!field || (field->offset != (fdesc->offset + struct_offset))) {
4330                                         if (!result)
4331                                                 result = g_string_new ("");
4332                                         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));
4333                                 }
4334                         }
4335                 }
4336         }
4337         if (result)
4338                 return g_string_free (result, FALSE);
4339         return NULL;
4340 }
4341
4342 char*
4343 mono_verify_corlib () {
4344         return check_corlib (mono_defaults.corlib);
4345 }
4346
4347