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