ppc changes
[mono.git] / mono / metadata / verify.c
1
2 #include <mono/metadata/object.h>
3 #include <mono/metadata/verify.h>
4 #include <mono/metadata/tabledefs.h>
5 #include <mono/metadata/mono-endian.h>
6 #include <string.h>
7 #include <signal.h>
8 #include <ctype.h>
9
10 /*
11  * Pull the list of opcodes
12  */
13 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
14         a = i,
15
16 enum {
17 #include "mono/cil/opcode.def"
18         LAST = 0xff
19 };
20 #undef OPDEF
21
22 void
23 mono_free_verify_list (GSList *list)
24 {
25         MonoVerifyInfo* info;
26         GSList *tmp;
27
28         for (tmp = list; tmp; tmp = tmp->next) {
29                 info = tmp->data;
30                 g_free (info->message);
31                 g_free (info);
32         }
33         g_slist_free (list);
34 }
35
36 #define ADD_ERROR(list,msg)     \
37         do {    \
38                 MonoVerifyInfo *vinfo = g_new (MonoVerifyInfo, 1);      \
39                 vinfo->status = MONO_VERIFY_ERROR;      \
40                 vinfo->message = (msg); \
41                 (list) = g_slist_prepend ((list), vinfo);       \
42         } while (0)
43
44 #define ADD_WARN(list,code,msg) \
45         do {    \
46                 MonoVerifyInfo *vinfo = g_new (MonoVerifyInfo, 1);      \
47                 vinfo->status = (code); \
48                 vinfo->message = (msg); \
49                 (list) = g_slist_prepend ((list), vinfo);       \
50         } while (0)
51
52 static const char*
53 valid_cultures[] = {
54         "ar-SA", "ar-IQ", "ar-EG", "ar-LY",
55         "ar-DZ", "ar-MA", "ar-TN", "ar-OM",
56         "ar-YE", "ar-SY", "ar-JO", "ar-LB",
57         "ar-KW", "ar-AE", "ar-BH", "ar-QA",
58         "bg-BG", "ca-ES", "zh-TW", "zh-CN",
59         "zh-HK", "zh-SG", "zh-MO", "cs-CZ",
60         "da-DK", "de-DE", "de-CH", "de-AT",
61         "de-LU", "de-LI", "el-GR", "en-US",
62         "en-GB", "en-AU", "en-CA", "en-NZ",
63         "en-IE", "en-ZA", "en-JM", "en-CB",
64         "en-BZ", "en-TT", "en-ZW", "en-PH",
65         "es-ES-Ts", "es-MX", "es-ES-Is", "es-GT",
66         "es-CR", "es-PA", "es-DO", "es-VE",
67         "es-CO", "es-PE", "es-AR", "es-EC",
68         "es-CL", "es-UY", "es-PY", "es-BO",
69         "es-SV", "es-HN", "es-NI", "es-PR",
70         "Fi-FI", "fr-FR", "fr-BE", "fr-CA",
71         "Fr-CH", "fr-LU", "fr-MC", "he-IL",
72         "hu-HU", "is-IS", "it-IT", "it-CH",
73         "Ja-JP", "ko-KR", "nl-NL", "nl-BE",
74         "nb-NO", "nn-NO", "pl-PL", "pt-BR",
75         "pt-PT", "ro-RO", "ru-RU", "hr-HR",
76         "Lt-sr-SP", "Cy-sr-SP", "sk-SK", "sq-AL",
77         "sv-SE", "sv-FI", "th-TH", "tr-TR",
78         "ur-PK", "id-ID", "uk-UA", "be-BY",
79         "sl-SI", "et-EE", "lv-LV", "lt-LT",
80         "fa-IR", "vi-VN", "hy-AM", "Lt-az-AZ",
81         "Cy-az-AZ",
82         "eu-ES", "mk-MK", "af-ZA",
83         "ka-GE", "fo-FO", "hi-IN", "ms-MY",
84         "ms-BN", "kk-KZ", "ky-KZ", "sw-KE",
85         "Lt-uz-UZ", "Cy-uz-UZ", "tt-TA", "pa-IN",
86         "gu-IN", "ta-IN", "te-IN", "kn-IN",
87         "mr-IN", "sa-IN", "mn-MN", "gl-ES",
88         "kok-IN", "syr-SY", "div-MV",
89         NULL
90 };
91
92 static int
93 is_valid_culture (const char *cname)
94 {
95         int i;
96         int found;
97                         
98         found = *cname == 0;
99         for (i = 0; !found && valid_cultures [i]; ++i) {
100                 if (g_strcasecmp (valid_cultures [i], cname))
101                         found = 1;
102         }
103         return found;
104 }
105
106 static int
107 is_valid_assembly_flags (guint32 flags) {
108         /* Metadata: 22.1.2 */
109         flags &= ~(0x8000 | 0x4000); /* ignore reserved bits 0x0030? */
110         return ((flags == 1) || (flags == 0));
111 }
112
113 static int
114 is_valid_blob (MonoImage *image, guint32 index, int notnull)
115 {
116         guint32 size;
117         const char *p, *send;
118         
119         if (index >= image->heap_blob.size)
120                 return 0;
121         p = mono_metadata_blob_heap (image, index);
122         size = mono_metadata_decode_blob_size (p, &send);
123         if (index + size + (send-p) > image->heap_blob.size)
124                 return 0;
125         if (notnull && !size)
126                 return 0;
127         return 1;
128 }
129
130 static const char*
131 is_valid_string (MonoImage *image, guint32 index, int notnull)
132 {
133         const char *p, *send, *res;
134         
135         if (index >= image->heap_strings.size)
136                 return NULL;
137         res = p = mono_metadata_string_heap (image, index);
138         send = mono_metadata_string_heap (image, image->heap_strings.size - 1);
139         if (notnull && !*p)
140                 return 0;
141         /* 
142          * FIXME: should check it's a valid utf8 string, too.
143          */
144         while (p <= send) {
145                 if (!*p)
146                         return res;
147                 ++p;
148         }
149         return *p? NULL: res;
150 }
151
152 static int
153 is_valid_cls_ident (const char *p)
154 {
155         /*
156          * FIXME: we need the full unicode glib support for this.
157          * Check: http://www.unicode.org/unicode/reports/tr15/Identifier.java
158          * We do the lame thing for now.
159          */
160         if (!isalpha (*p))
161                 return 0;
162         ++p;
163         while (*p) {
164                 if (!isalnum (*p) && *p != '_')
165                         return 0;
166                 ++p;
167         }
168         return 1;
169 }
170
171 static int
172 is_valid_filename (const char *p)
173 {
174         if (!*p)
175                 return 0;
176         return strpbrk (p, "\\//:")? 0: 1;
177 }
178
179 static GSList*
180 verify_assembly_table (MonoImage *image, GSList *list, int level)
181 {
182         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
183         guint32 cols [MONO_ASSEMBLY_SIZE];
184         const char *p;
185
186         if (level & MONO_VERIFY_ERROR) {
187                 if (t->rows > 1)
188                         ADD_ERROR (list, g_strdup ("Assembly table may only have 0 or 1 rows"));
189                 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
190                 
191                 switch (cols [MONO_ASSEMBLY_HASH_ALG]) {
192                 case ASSEMBLY_HASH_NONE:
193                 case ASSEMBLY_HASH_MD5:
194                 case ASSEMBLY_HASH_SHA1:
195                         break;
196                 default:
197                         ADD_ERROR (list, g_strdup_printf ("Hash algorithm 0x%x unknown", cols [MONO_ASSEMBLY_HASH_ALG]));
198                 }
199                 
200                 if (!is_valid_assembly_flags (cols [MONO_ASSEMBLY_FLAGS]))
201                         ADD_ERROR (list, g_strdup_printf ("Invalid flags in assembly: 0x%x", cols [MONO_ASSEMBLY_FLAGS]));
202                 
203                 if (!is_valid_blob (image, cols [MONO_ASSEMBLY_PUBLIC_KEY], FALSE))
204                         ADD_ERROR (list, g_strdup ("Assembly public key is an invalid index"));
205                 
206                 if (!(p = is_valid_string (image, cols [MONO_ASSEMBLY_NAME], TRUE))) {
207                         ADD_ERROR (list, g_strdup ("Assembly name is invalid"));
208                 } else {
209                         if (strpbrk (p, ":\\/."))
210                                 ADD_ERROR (list, g_strdup_printf ("Assembly name `%s' contains invalid chars", p));
211                 }
212
213                 if (!(p = is_valid_string (image, cols [MONO_ASSEMBLY_CULTURE], FALSE))) {
214                         ADD_ERROR (list, g_strdup ("Assembly culture is an invalid index"));
215                 } else {
216                         if (!is_valid_culture (p))
217                                 ADD_ERROR (list, g_strdup_printf ("Assembly culture `%s' is invalid", p));
218                 }
219         }
220         return list;
221 }
222
223 static GSList*
224 verify_assemblyref_table (MonoImage *image, GSList *list, int level)
225 {
226         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
227         guint32 cols [MONO_ASSEMBLYREF_SIZE];
228         const char *p;
229         int i;
230
231         if (level & MONO_VERIFY_ERROR) {
232                 for (i = 0; i < t->rows; ++i) {
233                         mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
234                         if (!is_valid_assembly_flags (cols [MONO_ASSEMBLYREF_FLAGS]))
235                                 ADD_ERROR (list, g_strdup_printf ("Invalid flags in assemblyref row %d: 0x%x", i + 1, cols [MONO_ASSEMBLY_FLAGS]));
236                 
237                         if (!is_valid_blob (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], FALSE))
238                                 ADD_ERROR (list, g_strdup_printf ("AssemblyRef public key in row %d is an invalid index", i + 1));
239                 
240                         if (!(p = is_valid_string (image, cols [MONO_ASSEMBLYREF_CULTURE], FALSE))) {
241                                 ADD_ERROR (list, g_strdup_printf ("AssemblyRef culture in row %d is invalid", i + 1));
242                         } else {
243                                 if (!is_valid_culture (p))
244                                         ADD_ERROR (list, g_strdup_printf ("AssemblyRef culture `%s' in row %d is invalid", p, i + 1));
245                         }
246
247                         if (cols [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob (image, cols [MONO_ASSEMBLYREF_HASH_VALUE], TRUE))
248                                 ADD_ERROR (list, g_strdup_printf ("AssemblyRef hash value in row %d is invalid or not null and empty", i + 1));
249                 }
250         }
251         if (level & MONO_VERIFY_WARNING) {
252                 /* check for duplicated rows */
253                 for (i = 0; i < t->rows; ++i) {
254                 }
255         }
256         return list;
257 }
258
259 static GSList*
260 verify_class_layout_table (MonoImage *image, GSList *list, int level)
261 {
262         MonoTableInfo *t = &image->tables [MONO_TABLE_CLASSLAYOUT];
263         MonoTableInfo *tdef = &image->tables [MONO_TABLE_TYPEDEF];
264         guint32 cols [MONO_CLASS_LAYOUT_SIZE];
265         guint32 value, i;
266         
267         if (level & MONO_VERIFY_ERROR) {
268                 for (i = 0; i < t->rows; ++i) {
269                         mono_metadata_decode_row (t, i, cols, MONO_CLASS_LAYOUT_SIZE);
270
271                         if (cols [MONO_CLASS_LAYOUT_PARENT] > tdef->rows || !cols [MONO_CLASS_LAYOUT_PARENT]) {
272                                 ADD_ERROR (list, g_strdup_printf ("Parent in class layout is invalid in row %d", i + 1));
273                         } else {
274                                 value = mono_metadata_decode_row_col (tdef, cols [MONO_CLASS_LAYOUT_PARENT] - 1, MONO_TYPEDEF_FLAGS);
275                                 if (value & TYPE_ATTRIBUTE_INTERFACE)
276                                         ADD_ERROR (list, g_strdup_printf ("Parent in class layout row %d is an interface", i + 1));
277                                 if (value & TYPE_ATTRIBUTE_AUTO_LAYOUT)
278                                         ADD_ERROR (list, g_strdup_printf ("Parent in class layout row %d is AutoLayout", i + 1));
279                                 if (value & TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT) {
280                                         switch (cols [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
281                                         case 0: case 1: case 2: case 4: case 8: case 16:
282                                         case 32: case 64: case 128: break;
283                                         default:
284                                                 ADD_ERROR (list, g_strdup_printf ("Packing size %d in class layout row %d is invalid", cols [MONO_CLASS_LAYOUT_PACKING_SIZE], i + 1));
285                                         }
286                                 } else if (value & TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
287                                         /*
288                                          * FIXME: LAMESPEC: it claims it must be 0 (it's 1, instead).
289                                         if (cols [MONO_CLASS_LAYOUT_PACKING_SIZE])
290                                                 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));
291                                         */
292                                 }
293                                 /*
294                                  * FIXME: we need to check that if class size != 0, 
295                                  * it needs to be greater than the class calculated size.
296                                  * If parent is a valuetype it also needs to be smaller than
297                                  * 1 MByte (0x100000 bytes).
298                                  * To do both these checks we need to load the referenced 
299                                  * assemblies, though (the spec claims we didn't have to, bah).
300                                  */
301                                 /* 
302                                  * We need to check that the parent types have the samme layout 
303                                  * type as well.
304                                  */
305                         }
306                 }
307         }
308         
309         return list;
310 }
311
312 static GSList*
313 verify_constant_table (MonoImage *image, GSList *list, int level)
314 {
315         MonoTableInfo *t = &image->tables [MONO_TABLE_CONSTANT];
316         guint32 cols [MONO_CONSTANT_SIZE];
317         guint32 value, i;
318         GHashTable *dups = g_hash_table_new (g_direct_hash, g_direct_equal);
319         
320         for (i = 0; i < t->rows; ++i) {
321                 mono_metadata_decode_row (t, i, cols, MONO_CONSTANT_SIZE);
322
323                 if (level & MONO_VERIFY_ERROR)
324                         if (g_hash_table_lookup (dups, GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT])))
325                                 ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is duplicated in Constant row %d", cols [MONO_CONSTANT_PARENT], i + 1));
326                 g_hash_table_insert (dups, GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT]),
327                                 GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT]));
328
329                 switch (cols [MONO_CONSTANT_TYPE]) {
330                 case MONO_TYPE_U1: /* LAMESPEC: it says I1...*/
331                 case MONO_TYPE_U2:
332                 case MONO_TYPE_U4:
333                 case MONO_TYPE_U8:
334                         if (level & MONO_VERIFY_CLS)
335                                 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));
336                 case MONO_TYPE_BOOLEAN:
337                 case MONO_TYPE_CHAR:
338                 case MONO_TYPE_I1:
339                 case MONO_TYPE_I2:
340                 case MONO_TYPE_I4:
341                 case MONO_TYPE_I8:
342                 case MONO_TYPE_R4:
343                 case MONO_TYPE_R8:
344                 case MONO_TYPE_STRING:
345                 case MONO_TYPE_CLASS:
346                         break;
347                 default:
348                         if (level & MONO_VERIFY_ERROR)
349                                 ADD_ERROR (list, g_strdup_printf ("Type 0x%x is invalid in Constant row %d", cols [MONO_CONSTANT_TYPE], i + 1));
350                 }
351                 if (level & MONO_VERIFY_ERROR) {
352                         value = cols [MONO_CONSTANT_PARENT] >> HASCONSTANT_BITS;
353                         switch (cols [MONO_CONSTANT_PARENT] & HASCONSTANT_MASK) {
354                         case HASCONSTANT_FIEDDEF:
355                                 if (value > image->tables [MONO_TABLE_FIELD].rows)
356                                         ADD_ERROR (list, g_strdup_printf ("Parent (field) is invalid in Constant row %d", i + 1));
357                                 break;
358                         case HASCONSTANT_PARAM:
359                                 if (value > image->tables [MONO_TABLE_PARAM].rows)
360                                         ADD_ERROR (list, g_strdup_printf ("Parent (param) is invalid in Constant row %d", i + 1));
361                                 break;
362                         case HASCONSTANT_PROPERTY:
363                                 if (value > image->tables [MONO_TABLE_PROPERTY].rows)
364                                         ADD_ERROR (list, g_strdup_printf ("Parent (property) is invalid in Constant row %d", i + 1));
365                                 break;
366                         default:
367                                 ADD_ERROR (list, g_strdup_printf ("Parent is invalid in Constant row %d", i + 1));
368                                 break;
369                         }
370                 }
371                 if (level & MONO_VERIFY_CLS) {
372                         /* 
373                          * FIXME: verify types is consistent with the enum type
374                          * is parent is an enum.
375                          */
376                 }
377         }
378         g_hash_table_destroy (dups);
379         return list;
380 }
381
382 static GSList*
383 verify_event_map_table (MonoImage *image, GSList *list, int level)
384 {
385         MonoTableInfo *t = &image->tables [MONO_TABLE_EVENTMAP];
386         guint32 cols [MONO_EVENT_MAP_SIZE];
387         guint32 i, last_event;
388         GHashTable *dups = g_hash_table_new (g_direct_hash, g_direct_equal);
389
390         last_event = 0;
391
392         for (i = 0; i < t->rows; ++i) {
393                 mono_metadata_decode_row (t, i, cols, MONO_EVENT_MAP_SIZE);
394                 if (level & MONO_VERIFY_ERROR)
395                         if (g_hash_table_lookup (dups, GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT])))
396                                 ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is duplicated in Event Map row %d", cols [MONO_EVENT_MAP_PARENT], i + 1));
397                 g_hash_table_insert (dups, GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT]),
398                                 GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT]));
399                 if (level & MONO_VERIFY_ERROR) {
400                         if (cols [MONO_EVENT_MAP_PARENT] > image->tables [MONO_TABLE_TYPEDEF].rows)
401                                 ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is invalid in Event Map row %d", cols [MONO_EVENT_MAP_PARENT], i + 1));
402                         if (cols [MONO_EVENT_MAP_EVENTLIST] > image->tables [MONO_TABLE_EVENT].rows)
403                                 ADD_ERROR (list, g_strdup_printf ("EventList 0x%08x is invalid in Event Map row %d", cols [MONO_EVENT_MAP_EVENTLIST], i + 1));
404
405                         if (cols [MONO_EVENT_MAP_EVENTLIST] <= last_event)
406                                 ADD_ERROR (list, g_strdup_printf ("EventList overlap in Event Map row %d", i + 1));
407                         last_event = cols [MONO_EVENT_MAP_EVENTLIST];
408                 }
409         }
410
411         g_hash_table_destroy (dups);
412         return list;
413 }
414
415 static GSList*
416 verify_event_table (MonoImage *image, GSList *list, int level)
417 {
418         MonoTableInfo *t = &image->tables [MONO_TABLE_EVENT];
419         guint32 cols [MONO_EVENT_SIZE];
420         const char *p;
421         guint32 value, i;
422         
423         for (i = 0; i < t->rows; ++i) {
424                 mono_metadata_decode_row (t, i, cols, MONO_EVENT_SIZE);
425
426                 if (cols [MONO_EVENT_FLAGS] & ~(EVENT_SPECIALNAME|EVENT_RTSPECIALNAME)) {
427                         if (level & MONO_VERIFY_ERROR)
428                                 ADD_ERROR (list, g_strdup_printf ("Flags 0x%04x invalid in Event row %d", cols [MONO_EVENT_FLAGS], i + 1));
429                 }
430                 if (!(p = is_valid_string (image, cols [MONO_EVENT_NAME], TRUE))) {
431                         if (level & MONO_VERIFY_ERROR)
432                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in Event row %d", i + 1));
433                 } else {
434                         if (level & MONO_VERIFY_CLS) {
435                                 if (!is_valid_cls_ident (p))
436                                         ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Invalid CLS name '%s` in Event row %d", p, i + 1));
437                         }
438                 }
439                 
440                 if (level & MONO_VERIFY_ERROR && cols [MONO_EVENT_TYPE]) {
441                         value = cols [MONO_EVENT_TYPE] >> TYPEDEFORREF_BITS;
442                         switch (cols [MONO_EVENT_TYPE] & TYPEDEFORREF_MASK) {
443                         case TYPEDEFORREF_TYPEDEF:
444                                 if (!value || value > image->tables [MONO_TABLE_TYPEDEF].rows)
445                                         ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
446                                 break;
447                         case TYPEDEFORREF_TYPEREF:
448                                 if (!value || value > image->tables [MONO_TABLE_TYPEREF].rows)
449                                         ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
450                                 break;
451                         case TYPEDEFORREF_TYPESPEC:
452                                 if (!value || value > image->tables [MONO_TABLE_TYPESPEC].rows)
453                                         ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
454                                 break;
455                         default:
456                                 ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
457                         }
458                 }
459                 /*
460                  * FIXME: check that there is 1 add and remove row in methodsemantics
461                  * and 0 or 1 raise and 0 or more other (maybe it's better to check for 
462                  * these while checking methodsemantics).
463                  * check for duplicated names for the same type [ERROR]
464                  * check for CLS duplicate names for the same type [CLS]
465                  */
466         }
467         return list;
468 }
469
470 static GSList*
471 verify_field_table (MonoImage *image, GSList *list, int level)
472 {
473         MonoTableInfo *t = &image->tables [MONO_TABLE_FIELD];
474         guint32 cols [MONO_FIELD_SIZE];
475         const char *p;
476         guint32 i, flags;
477         
478         for (i = 0; i < t->rows; ++i) {
479                 mono_metadata_decode_row (t, i, cols, MONO_FIELD_SIZE);
480                 /*
481                  * Check this field has only one owner and that the owner is not 
482                  * an interface (done in verify_typedef_table() )
483                  */
484                 flags = cols [MONO_FIELD_FLAGS];
485                 switch (flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) {
486                 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
487                 case FIELD_ATTRIBUTE_PRIVATE:
488                 case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
489                 case FIELD_ATTRIBUTE_ASSEMBLY:
490                 case FIELD_ATTRIBUTE_FAMILY:
491                 case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
492                 case FIELD_ATTRIBUTE_PUBLIC:
493                         break;
494                 default:
495                         if (level & MONO_VERIFY_ERROR)
496                                 ADD_ERROR (list, g_strdup_printf ("Invalid access mask in Field row %d", i + 1));
497                         break;
498                 }
499                 if (level & MONO_VERIFY_ERROR) {
500                         if ((flags & FIELD_ATTRIBUTE_LITERAL) && (flags & FIELD_ATTRIBUTE_INIT_ONLY))
501                                 ADD_ERROR (list, g_strdup_printf ("Literal and InitOnly cannot be both set in Field row %d", i + 1));
502                         if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
503                                 ADD_ERROR (list, g_strdup_printf ("Literal needs also Static set in Field row %d", i + 1));
504                         if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
505                                 ADD_ERROR (list, g_strdup_printf ("RTSpecialName needs also SpecialName set in Field row %d", i + 1));
506                         /*
507                          * FIXME: check there is only ono owner in the respective table.
508                          * if (flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
509                          * if (flags & FIELD_ATTRIBUTE_HAS_DEFAULT)
510                          * if (flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA)
511                          */
512                 }
513                 if (!(p = is_valid_string (image, cols [MONO_FIELD_NAME], TRUE))) {
514                         if (level & MONO_VERIFY_ERROR)
515                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in Field row %d", i + 1));
516                 } else {
517                         if (level & MONO_VERIFY_CLS) {
518                                 if (!is_valid_cls_ident (p))
519                                         ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Invalid CLS name '%s` in Field row %d", p, i + 1));
520                         }
521                 }
522                 /*
523                  * check signature.
524                  * if owner is module needs to be static, access mask needs to be compilercontrolled,
525                  * public or private (not allowed in cls mode).
526                  * if owner is an enum ...
527                  */
528                 
529                 
530         }
531         return list;
532 }
533
534 static GSList*
535 verify_file_table (MonoImage *image, GSList *list, int level)
536 {
537         MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
538         guint32 cols [MONO_FILE_SIZE];
539         const char *p;
540         guint32 i;
541         GHashTable *dups = g_hash_table_new (g_str_hash, g_str_equal);
542         
543         for (i = 0; i < t->rows; ++i) {
544                 mono_metadata_decode_row (t, i, cols, MONO_FILE_SIZE);
545                 if (level & MONO_VERIFY_ERROR) {
546                         if (cols [MONO_FILE_FLAGS] != FILE_CONTAINS_METADATA && cols [MONO_FILE_FLAGS] != FILE_CONTAINS_NO_METADATA)
547                                 ADD_ERROR (list, g_strdup_printf ("Invalid flags in File row %d", i + 1));
548                         if (!is_valid_blob (image, cols [MONO_FILE_HASH_VALUE], TRUE))
549                                 ADD_ERROR (list, g_strdup_printf ("File hash value in row %d is invalid or not null and empty", i + 1));
550                 }
551                 if (!(p = is_valid_string (image, cols [MONO_FILE_NAME], TRUE))) {
552                         if (level & MONO_VERIFY_ERROR)
553                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in File row %d", i + 1));
554                 } else {
555                         if (level & MONO_VERIFY_ERROR) {
556                                 if (!is_valid_filename (p))
557                                         ADD_ERROR (list, g_strdup_printf ("Invalid name '%s` in File row %d", p, i + 1));
558                                 else if (g_hash_table_lookup (dups, p)) {
559                                         ADD_ERROR (list, g_strdup_printf ("Duplicate name '%s` in File row %d", p, i + 1));
560                                 }
561                                 g_hash_table_insert (dups, (gpointer)p, (gpointer)p);
562                         }
563                 }
564                 /*
565                  * FIXME: I don't understand what this means:
566                  * If this module contains a row in the Assembly table (that is, if this module "holds the manifest") 
567                  * then there shall not be any row in the File table for this module - i.e., no self-reference  [ERROR]
568                  */
569
570         }
571         if (level & MONO_VERIFY_WARNING) {
572                 if (!t->rows && image->tables [MONO_TABLE_EXPORTEDTYPE].rows)
573                         ADD_WARN (list, MONO_VERIFY_WARNING, g_strdup ("ExportedType table should be empty if File table is empty"));
574         }
575         g_hash_table_destroy (dups);
576         return list;
577 }
578
579 static GSList*
580 verify_moduleref_table (MonoImage *image, GSList *list, int level)
581 {
582         MonoTableInfo *t = &image->tables [MONO_TABLE_MODULEREF];
583         MonoTableInfo *tfile = &image->tables [MONO_TABLE_FILE];
584         guint32 cols [MONO_MODULEREF_SIZE];
585         const char *p, *pf;
586         guint32 found, i, j, value;
587         GHashTable *dups = g_hash_table_new (g_str_hash, g_str_equal);
588         
589         for (i = 0; i < t->rows; ++i) {
590                 mono_metadata_decode_row (t, i, cols, MONO_MODULEREF_SIZE);
591                 if (!(p = is_valid_string (image, cols [MONO_MODULEREF_NAME], TRUE))) {
592                         if (level & MONO_VERIFY_ERROR)
593                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in ModuleRef row %d", i + 1));
594                 } else {
595                         if (level & MONO_VERIFY_ERROR) {
596                                 if (!is_valid_filename (p))
597                                         ADD_ERROR (list, g_strdup_printf ("Invalid name '%s` in ModuleRef row %d", p, i + 1));
598                                 else if (g_hash_table_lookup (dups, p)) {
599                                         ADD_WARN (list, MONO_VERIFY_WARNING, g_strdup_printf ("Duplicate name '%s` in ModuleRef row %d", p, i + 1));
600                                         g_hash_table_insert (dups, (gpointer)p, (gpointer)p);
601                                         found = 0;
602                                         for (j = 0; j < tfile->rows; ++j) {
603                                                 value = mono_metadata_decode_row_col (tfile, j, MONO_FILE_NAME);
604                                                 if ((pf = is_valid_string (image, value, TRUE)))
605                                                         if (strcmp (p, pf) == 0) {
606                                                                 found = 1;
607                                                                 break;
608                                                         }
609                                         }
610                                         if (!found)
611                                                 ADD_ERROR (list, g_strdup_printf ("Name '%s` in ModuleRef row %d doesn't have a match in File table", p, i + 1));
612                                 }
613                         }
614                 }
615         }
616         g_hash_table_destroy (dups);
617         return list;
618 }
619
620 static GSList*
621 verify_standalonesig_table (MonoImage *image, GSList *list, int level)
622 {
623         MonoTableInfo *t = &image->tables [MONO_TABLE_STANDALONESIG];
624         guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE];
625         const char *p;
626         guint32 i;
627
628         for (i = 0; i < t->rows; ++i) {
629                 mono_metadata_decode_row (t, i, cols, MONO_STAND_ALONE_SIGNATURE_SIZE);
630                 if (level & MONO_VERIFY_ERROR) {
631                         if (!is_valid_blob (image, cols [MONO_STAND_ALONE_SIGNATURE], TRUE)) {
632                                 ADD_ERROR (list, g_strdup_printf ("Signature is invalid in StandAloneSig row %d", i + 1));
633                         } else {
634                                 p = mono_metadata_blob_heap (image, cols [MONO_STAND_ALONE_SIGNATURE]);
635                                 /* FIXME: check it's a valid locals or method sig.*/
636                         }
637                 }
638         }
639         return list;
640 }
641
642 GSList*
643 mono_image_verify_tables (MonoImage *image, int level)
644 {
645         GSList *error_list = NULL;
646
647         error_list = verify_assembly_table (image, error_list, level);
648         /* 
649          * AssemblyOS, AssemblyProcessor, AssemblyRefOs and
650          * AssemblyRefProcessor should be ignored, 
651          * though we may want to emit a warning, since it should not 
652          * be present in a PE file.
653          */
654         error_list = verify_assemblyref_table (image, error_list, level);
655         error_list = verify_class_layout_table (image, error_list, level);
656         error_list = verify_constant_table (image, error_list, level);
657         /*
658          * cutom attribute, declsecurity 
659          */
660         error_list = verify_event_map_table (image, error_list, level);
661         error_list = verify_event_table (image, error_list, level);
662         error_list = verify_field_table (image, error_list, level);
663         error_list = verify_file_table (image, error_list, level);
664         error_list = verify_moduleref_table (image, error_list, level);
665         error_list = verify_standalonesig_table (image, error_list, level);
666
667         return g_slist_reverse (error_list);
668 }
669
670 enum {
671         TYPE_INVALID = 0, /* leave at 0. */
672         TYPE_INT32 = 1,
673         TYPE_INT64 = 2,
674         TYPE_NINT  = 3,
675         TYPE_FLOAT = 4,
676         TYPE_MANP = 5,
677         TYPE_OBJREF = 6,
678         TYPE_MAX = 7
679 };
680
681 const static unsigned char 
682 valid_binops [TYPE_MAX] [TYPE_MAX] = {
683         {TYPE_INVALID},
684         {TYPE_INVALID, TYPE_INT32,   TYPE_INVALID, TYPE_NINT,    TYPE_INVALID, TYPE_MANP},
685         {TYPE_INVALID, TYPE_INVALID, TYPE_INT64,   TYPE_INVALID},
686         {TYPE_INVALID, TYPE_NINT,    TYPE_INVALID, TYPE_NINT,    TYPE_INVALID, TYPE_MANP},
687         {TYPE_INVALID, TYPE_INVALID, TYPE_INVALID, TYPE_INVALID, TYPE_FLOAT},
688         {TYPE_INVALID, TYPE_MANP,    TYPE_INVALID, TYPE_MANP,    TYPE_INVALID, TYPE_NINT},
689         {TYPE_INVALID}
690                        /* int32 */   /* int64 */   /* native */  /* float */   /* managed p */ /* objref */
691 };
692
693 const static unsigned char 
694 valid_unnops [TYPE_MAX] = {
695         TYPE_INVALID, TYPE_INT32,    TYPE_INT64,   TYPE_NINT,    TYPE_FLOAT,   TYPE_INVALID
696                        /* int32 */   /* int64 */   /* native */  /* float */   /* managed p */ /* objref */
697 };
698
699 /* note: the resulting type is always a boolean */
700 const static unsigned char 
701 valid_bincomp [TYPE_MAX] [TYPE_MAX] = {
702         {TYPE_INVALID},
703         {TYPE_INVALID, TYPE_INT32,   TYPE_INVALID, TYPE_INT32,   TYPE_INVALID},
704         {TYPE_INVALID, TYPE_INVALID, TYPE_INT32,   TYPE_INVALID},
705         {TYPE_INVALID, TYPE_INT32,   TYPE_INVALID, TYPE_INT32,   TYPE_INVALID, TYPE_INT32},
706         {TYPE_INVALID, TYPE_INVALID, TYPE_INVALID, TYPE_INVALID, TYPE_INT32},
707         {TYPE_INVALID, TYPE_INVALID, TYPE_INVALID, TYPE_INT32,   TYPE_INVALID, TYPE_INT32},
708         {TYPE_INVALID, TYPE_INVALID, TYPE_INVALID, TYPE_INVALID, TYPE_INVALID, TYPE_INVALID, TYPE_INT32}
709                        /* int32 */   /* int64 */   /* native */  /* float */   /* managed p */ /* objref */
710 };
711
712 const static unsigned char 
713 valid_intops [TYPE_MAX] [TYPE_MAX] = {
714         {TYPE_INVALID},
715         {TYPE_INVALID, TYPE_INT32,   TYPE_INVALID, TYPE_NINT},
716         {TYPE_INVALID, TYPE_INVALID, TYPE_INT64},
717         {TYPE_INVALID, TYPE_NINT,    TYPE_INVALID, TYPE_NINT},
718         {TYPE_INVALID}
719 };
720
721 const static unsigned char 
722 valid_shiftops [TYPE_MAX] [TYPE_MAX] = {
723         {TYPE_INVALID},
724         {TYPE_INVALID, TYPE_INT32,   TYPE_INVALID, TYPE_INT32},
725         {TYPE_INVALID, TYPE_INT64,   TYPE_INVALID, TYPE_INT64},
726         {TYPE_INVALID, TYPE_NINT,    TYPE_INVALID, TYPE_NINT},
727         {TYPE_INVALID}
728 };
729
730 #define ADD_INVALID(list,msg)   \
731         do {    \
732                 MonoVerifyInfo *vinfo = g_new (MonoVerifyInfo, 1);      \
733                 vinfo->status = MONO_VERIFY_ERROR;      \
734                 vinfo->message = (msg); \
735                 (list) = g_slist_prepend ((list), vinfo);       \
736                 G_BREAKPOINT ();        \
737                 goto invalid_cil;       \
738         } while (0)
739
740 #define CHECK_STACK_UNDERFLOW(num)      \
741         do {    \
742                 if (cur_stack < (num))  \
743                         ADD_INVALID (list, g_strdup_printf ("Stack underflow at 0x%04x", ip_offset));   \
744         } while (0)
745
746 #define CHECK_STACK_OVERFLOW()  \
747         do {    \
748                 if (cur_stack >= max_stack)     \
749                         ADD_INVALID (list, g_strdup_printf ("Maxstack exceeded at 0x%04x", ip_offset)); \
750         } while (0)
751
752 enum {
753         PREFIX_UNALIGNED = 1,
754         PREFIX_VOLATILE  = 2,
755         PREFIX_TAIL      = 4,
756         PREFIX_ADDR_MASK = 3,
757         PREFIX_FUNC_MASK = 4
758 };
759
760 enum {
761         CODE_SEEN = 1
762 };
763
764 typedef struct {
765         MonoClass *klass;
766         int type;
767 } ILStackDesc;
768
769 typedef struct {
770         ILStackDesc *stack;
771         guint16 stack_count;
772         guint16 flags;
773 } ILCodeDesc;
774
775 static int
776 in_any_block (MonoMethodHeader *header, guint offset)
777 {
778         int i;
779         MonoExceptionClause *clause;
780
781         for (i = 0; i < header->num_clauses; ++i) {
782                 clause = &header->clauses [i];
783                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
784                         return 1;
785                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
786                         return 1;
787                 /* need to check filter ... */
788         }
789         return 0;
790 }
791
792 static int
793 in_same_block (MonoMethodHeader *header, guint offset, guint target)
794 {
795         int i;
796         MonoExceptionClause *clause;
797
798         for (i = 0; i < header->num_clauses; ++i) {
799                 clause = &header->clauses [i];
800                 if (MONO_OFFSET_IN_CLAUSE (clause, offset) && !MONO_OFFSET_IN_CLAUSE (clause, target))
801                         return 0;
802                 if (MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
803                         return 0;
804                 /* need to check filter ... */
805         }
806         return 1;
807 }
808
809 /*
810  * A leave can't escape a finally block 
811  */
812 static int
813 is_correct_leave (MonoMethodHeader *header, guint offset, guint target)
814 {
815         int i;
816         MonoExceptionClause *clause;
817
818         for (i = 0; i < header->num_clauses; ++i) {
819                 clause = &header->clauses [i];
820                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY && MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
821                         return 0;
822                 /* need to check filter ... */
823         }
824         return 1;
825 }
826
827 static int
828 can_merge_stack (ILCodeDesc *a, ILCodeDesc *b)
829 {
830         if (!b->flags & CODE_SEEN) {
831                 b->flags |= CODE_SEEN;
832                 b->stack_count = a->stack_count;
833                 /* merge types */
834                 return 1;
835         }
836         if (a->stack_count != b->stack_count)
837                 return 0;
838         /* merge types */
839         return 1;
840 }
841
842 /*
843  * FIXME: need to distinguish between valid and verifiable.
844  * Need to keep track of types on the stack.
845  * Verify types for opcodes.
846  */
847 GSList*
848 mono_method_verify (MonoMethod *method, int level)
849 {
850         MonoMethodHeader *header;
851         MonoMethodSignature *signature, *csig;
852         MonoMethod *cmethod;
853         MonoImage *image;
854         register const unsigned char *ip;
855         register const unsigned char *end;
856         const unsigned char *target; /* branch target */
857         int max_args, max_stack, cur_stack, i, n, need_merge, start;
858         guint32 token, ip_offset;
859         char *local_state = NULL;
860         GSList *list = NULL;
861         guint prefix = 0;
862         ILCodeDesc *code;
863
864         signature = method->signature;
865         header = ((MonoMethodNormal *)method)->header;
866         ip = header->code;
867         end = ip + header->code_size;
868         max_args = method->signature->param_count + method->signature->hasthis;
869         max_stack = header->max_stack;
870         need_merge = cur_stack = 0;
871         start = 1;
872         image = method->klass->image;
873         code = g_new0 (ILCodeDesc, header->code_size);
874
875         if (header->num_locals) {
876                 local_state = g_new (char, header->num_locals);
877                 memset (local_state, header->init_locals, header->num_locals);
878         }
879         g_print ("Method %s.%s::%s\n", method->klass->name_space, method->klass->name, method->name);
880
881         while (ip < end) {
882                 ip_offset = ip - header->code;
883                 g_print ("IL_%04x: %02x\n", ip_offset, *ip);
884                 if (start || !(code [ip_offset].flags & CODE_SEEN)) {
885                         if (start) {
886                                 code [ip_offset].stack_count = 0;
887                                 start = 0;
888                         } else {
889                                 code [ip_offset].stack_count = cur_stack;
890                         }
891                         code [ip_offset].flags |= CODE_SEEN;
892                 } else {
893                         /* stack merge */
894                         if (code [ip_offset].stack_count != cur_stack)
895                                 ADD_INVALID (list, g_strdup_printf ("Cannot merge stack states at 0x%04x", ip_offset));
896                 }
897                 if (need_merge) {
898                         if (!can_merge_stack (&code [ip_offset], &code [target - header->code]))
899                                 ADD_INVALID (list, g_strdup_printf ("Cannot merge stack states at 0x%04x", ip_offset));
900                         need_merge = 0;
901                 }
902
903                 switch (*ip) {
904                 case CEE_NOP:
905                 case CEE_BREAK: 
906                         ++ip;
907                         break;
908                 case CEE_LDARG_0:
909                 case CEE_LDARG_1:
910                 case CEE_LDARG_2:
911                 case CEE_LDARG_3:
912                         if (*ip - CEE_LDARG_0 >= max_args)
913                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", *ip - CEE_LDARG_0, ip_offset));
914                         CHECK_STACK_OVERFLOW ();
915                         ++cur_stack;
916                         ++ip;
917                         break;
918                 case CEE_LDLOC_0:
919                 case CEE_LDLOC_1:
920                 case CEE_LDLOC_2:
921                 case CEE_LDLOC_3:
922                         if (*ip - CEE_LDLOC_0 >= header->num_locals)
923                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", *ip - CEE_LDLOC_0, ip_offset));
924                         if (!local_state [*ip - CEE_LDLOC_0])
925                                 ADD_INVALID (list, g_strdup_printf ("Local var %d is initialized at 0x%04x", *ip - CEE_LDLOC_0, ip_offset));
926                         CHECK_STACK_OVERFLOW ();
927                         ++cur_stack;
928                         ++ip;
929                         break;
930                 case CEE_STLOC_0:
931                 case CEE_STLOC_1:
932                 case CEE_STLOC_2:
933                 case CEE_STLOC_3:
934                         if (*ip - CEE_STLOC_0 >= header->num_locals)
935                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", *ip - CEE_STLOC_0, ip_offset));
936                         local_state [*ip - CEE_STLOC_0] = 1;
937                         CHECK_STACK_UNDERFLOW (1);
938                         --cur_stack;
939                         ++ip;
940                         break;
941                 case CEE_LDARG_S:
942                 case CEE_LDARGA_S:
943                         if (ip [1] >= max_args)
944                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", ip [1], ip_offset));
945                         CHECK_STACK_OVERFLOW ();
946                         ++cur_stack;
947                         ip += 2;
948                         break;
949                 case CEE_STARG_S:
950                         if (ip [1] >= max_args)
951                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", ip [1], ip_offset));
952                         CHECK_STACK_UNDERFLOW (1);
953                         --cur_stack;
954                         ip += 2;
955                         break;
956                 case CEE_LDLOC_S:
957                 case CEE_LDLOCA_S:
958                         if (ip [1] >= header->num_locals)
959                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", ip [1], ip_offset));
960                         /* no need to check if the var is initialized if the address is taken */
961                         if (*ip == CEE_LDLOC_S && !local_state [ip [1]])
962                                 ADD_INVALID (list, g_strdup_printf ("Local var %d is initialized at 0x%04x", ip [1], ip_offset));
963                         CHECK_STACK_OVERFLOW ();
964                         ++cur_stack;
965                         ip += 2;
966                         break;
967                 case CEE_STLOC_S:
968                         if (ip [1] >= header->num_locals)
969                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", ip [1], ip_offset));
970                         local_state [ip [1]] = 1;
971                         CHECK_STACK_UNDERFLOW (1);
972                         --cur_stack;
973                         ip += 2;
974                         break;
975                 case CEE_LDNULL:
976                         CHECK_STACK_OVERFLOW ();
977                         ++cur_stack;
978                         ++ip;
979                         break;
980                 case CEE_LDC_I4_M1:
981                 case CEE_LDC_I4_0:
982                 case CEE_LDC_I4_1:
983                 case CEE_LDC_I4_2:
984                 case CEE_LDC_I4_3:
985                 case CEE_LDC_I4_4:
986                 case CEE_LDC_I4_5:
987                 case CEE_LDC_I4_6:
988                 case CEE_LDC_I4_7:
989                 case CEE_LDC_I4_8:
990                         CHECK_STACK_OVERFLOW ();
991                         ++cur_stack;
992                         ++ip;
993                         break;
994                 case CEE_LDC_I4_S:
995                         CHECK_STACK_OVERFLOW ();
996                         ++cur_stack;
997                         ip += 2;
998                         break;
999                 case CEE_LDC_I4:
1000                         CHECK_STACK_OVERFLOW ();
1001                         ++cur_stack;
1002                         ip += 5;
1003                         break;
1004                 case CEE_LDC_I8:
1005                         CHECK_STACK_OVERFLOW ();
1006                         ++cur_stack;
1007                         ip += 9;
1008                         break;
1009                 case CEE_LDC_R4:
1010                         CHECK_STACK_OVERFLOW ();
1011                         ++cur_stack;
1012                         ip += 5;
1013                         break;
1014                 case CEE_LDC_R8:
1015                         CHECK_STACK_OVERFLOW ();
1016                         ++cur_stack;
1017                         ip += 9;
1018                         break;
1019                 case CEE_UNUSED99: ++ip; break; /* warn/error instead? */
1020                 case CEE_DUP:
1021                         CHECK_STACK_UNDERFLOW (1);
1022                         CHECK_STACK_OVERFLOW ();
1023                         ++cur_stack;
1024                         ++ip;
1025                         break;
1026                 case CEE_POP:
1027                         CHECK_STACK_UNDERFLOW (1);
1028                         --cur_stack;
1029                         ++ip;
1030                         break;
1031                 case CEE_JMP:
1032                         if (cur_stack)
1033                                 ADD_INVALID (list, g_strdup_printf ("Eval stack must be empty in jmp at 0x%04x", ip_offset));
1034                         token = read32 (ip + 1);
1035                         if (in_any_block (header, ip_offset))
1036                                 ADD_INVALID (list, g_strdup_printf ("jmp cannot escape exception blocks at 0x%04x", ip_offset));
1037                         /*
1038                          * FIXME: check signature, retval, arguments etc.
1039                          */
1040                         ip += 5;
1041                         break;
1042                 case CEE_CALL:
1043                 case CEE_CALLVIRT:
1044                         token = read32 (ip + 1);
1045                         /*
1046                          * FIXME: we could just load the signature ...
1047                          */
1048                         cmethod = mono_get_method (image, token, NULL);
1049                         if (!cmethod)
1050                                 ADD_INVALID (list, g_strdup_printf ("Method 0x%08x not found at 0x%04x", token, ip_offset));
1051                         csig = cmethod->signature;
1052                         CHECK_STACK_UNDERFLOW (csig->param_count + csig->hasthis);
1053                         cur_stack -= csig->param_count + csig->hasthis;
1054                         if (csig->ret->type != MONO_TYPE_VOID) {
1055                                 CHECK_STACK_OVERFLOW ();
1056                                 ++cur_stack;
1057                         }
1058                         ip += 5;
1059                         break;
1060                 case CEE_CALLI:
1061                         token = read32 (ip + 1);
1062                         /*
1063                          * FIXME: check signature, retval, arguments etc.
1064                          */
1065                         ip += 5;
1066                         break;
1067                 case CEE_RET:
1068                         if (signature->ret->type != MONO_TYPE_VOID) {
1069                                 if (cur_stack != 1)
1070                                         ADD_INVALID (list, g_strdup_printf ("Stack not empty after ret at 0x%04x", ip_offset));
1071                                 --cur_stack;
1072                         } else {
1073                                 if (cur_stack)
1074                                         ADD_INVALID (list, g_strdup_printf ("Stack not empty after ret at 0x%04x", ip_offset));
1075                                 cur_stack = 0;
1076                         }
1077                         if (in_any_block (header, ip_offset))
1078                                 ADD_INVALID (list, g_strdup_printf ("ret cannot escape exception blocks at 0x%04x", ip_offset));
1079                         ++ip;
1080                         break;
1081                 case CEE_BR_S:
1082                         target = ip + (signed char)ip [1] + 2;
1083                         if (target >= end || target < header->code)
1084                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1085                         if (!in_same_block (header, ip_offset, target - header->code))
1086                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1087                         ip += 2;
1088                         start = 1;
1089                         break;
1090                 case CEE_BRFALSE_S:
1091                 case CEE_BRTRUE_S:
1092                         target = ip + (signed char)ip [1] + 2;
1093                         if (target >= end || target < header->code)
1094                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1095                         if (!in_same_block (header, ip_offset, target - header->code))
1096                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1097                         CHECK_STACK_UNDERFLOW (1);
1098                         --cur_stack;
1099                         ip += 2;
1100                         need_merge = 1;
1101                         break;
1102                 case CEE_BEQ_S:
1103                 case CEE_BGE_S:
1104                 case CEE_BGT_S:
1105                 case CEE_BLE_S:
1106                 case CEE_BLT_S:
1107                 case CEE_BNE_UN_S:
1108                 case CEE_BGE_UN_S:
1109                 case CEE_BGT_UN_S:
1110                 case CEE_BLE_UN_S:
1111                 case CEE_BLT_UN_S:
1112                         target = ip + (signed char)ip [1] + 2;
1113                         if (target >= end || target < header->code)
1114                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1115                         if (!in_same_block (header, ip_offset, target - header->code))
1116                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1117                         CHECK_STACK_UNDERFLOW (2);
1118                         cur_stack -= 2;
1119                         ip += 2;
1120                         need_merge = 1;
1121                         break;
1122                 case CEE_BR:
1123                         target = ip + (gint32)read32 (ip + 1) + 5;
1124                         if (target >= end || target < header->code)
1125                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1126                         if (!in_same_block (header, ip_offset, target - header->code))
1127                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1128                         ip += 5;
1129                         start = 1;
1130                         break;
1131                 case CEE_BRFALSE:
1132                 case CEE_BRTRUE:
1133                         target = ip + (gint32)read32 (ip + 1) + 5;
1134                         if (target >= end || target < header->code)
1135                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1136                         if (!in_same_block (header, ip_offset, target - header->code))
1137                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1138                         CHECK_STACK_UNDERFLOW (1);
1139                         --cur_stack;
1140                         ip += 5;
1141                         need_merge = 1;
1142                         break;
1143                 case CEE_BEQ:
1144                 case CEE_BGE:
1145                 case CEE_BGT:
1146                 case CEE_BLE:
1147                 case CEE_BLT:
1148                 case CEE_BNE_UN:
1149                 case CEE_BGE_UN:
1150                 case CEE_BGT_UN:
1151                 case CEE_BLE_UN:
1152                 case CEE_BLT_UN:
1153                         target = ip + (gint32)read32 (ip + 1) + 5;
1154                         if (target >= end || target < header->code)
1155                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1156                         if (!in_same_block (header, ip_offset, target - header->code))
1157                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1158                         CHECK_STACK_UNDERFLOW (2);
1159                         cur_stack -= 2;
1160                         ip += 5;
1161                         need_merge = 1;
1162                         break;
1163                 case CEE_SWITCH:
1164                         n = read32 (ip + 1);
1165                         target = ip + sizeof (guint32) * n;
1166                         /* FIXME: check that ip is in range (and within the same exception block) */
1167                         for (i = 0; i < n; ++i)
1168                                 if (target + (gint32) read32 (ip + 5 + i * sizeof (gint32)) >= end || target + (gint32) read32 (ip + 5 + i * sizeof (gint32)) < header->code)
1169                                         ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1170                         CHECK_STACK_UNDERFLOW (1);
1171                         --cur_stack;
1172                         ip += 5 + sizeof (guint32) * n;
1173                         break;
1174                 case CEE_LDIND_I1:
1175                 case CEE_LDIND_U1:
1176                 case CEE_LDIND_I2:
1177                 case CEE_LDIND_U2:
1178                 case CEE_LDIND_I4:
1179                 case CEE_LDIND_U4:
1180                 case CEE_LDIND_I8:
1181                 case CEE_LDIND_I:
1182                 case CEE_LDIND_R4:
1183                 case CEE_LDIND_R8:
1184                 case CEE_LDIND_REF:
1185                         CHECK_STACK_UNDERFLOW (1);
1186                         ++ip;
1187                         break;
1188                 case CEE_STIND_REF:
1189                 case CEE_STIND_I1:
1190                 case CEE_STIND_I2:
1191                 case CEE_STIND_I4:
1192                 case CEE_STIND_I8:
1193                 case CEE_STIND_R4:
1194                 case CEE_STIND_R8:
1195                         CHECK_STACK_UNDERFLOW (2);
1196                         cur_stack -= 2;
1197                         ++ip;
1198                         break;
1199                 case CEE_ADD:
1200                 case CEE_SUB:
1201                 case CEE_MUL:
1202                 case CEE_DIV:
1203                 case CEE_DIV_UN:
1204                 case CEE_REM:
1205                 case CEE_REM_UN:
1206                 case CEE_AND:
1207                 case CEE_OR:
1208                 case CEE_XOR:
1209                 case CEE_SHL:
1210                 case CEE_SHR:
1211                 case CEE_SHR_UN:
1212                         CHECK_STACK_UNDERFLOW (2);
1213                         --cur_stack;
1214                         ++ip;
1215                         break;
1216                 case CEE_NEG:
1217                 case CEE_NOT:
1218                 case CEE_CONV_I1:
1219                 case CEE_CONV_I2:
1220                 case CEE_CONV_I4:
1221                 case CEE_CONV_I8:
1222                 case CEE_CONV_R4:
1223                 case CEE_CONV_R8:
1224                 case CEE_CONV_U4:
1225                 case CEE_CONV_U8:
1226                         CHECK_STACK_UNDERFLOW (1);
1227                         ++ip;
1228                         break;
1229                 case CEE_CPOBJ:
1230                         token = read32 (ip + 1);
1231                         CHECK_STACK_UNDERFLOW (2);
1232                         cur_stack -= 2;
1233                         ip += 5;
1234                         break;
1235                 case CEE_LDOBJ:
1236                         token = read32 (ip + 1);
1237                         CHECK_STACK_UNDERFLOW (1);
1238                         ip += 5;
1239                         break;
1240                 case CEE_LDSTR:
1241                         token = read32 (ip + 1);
1242                         CHECK_STACK_OVERFLOW ();
1243                         ++cur_stack;
1244                         ip += 5;
1245                         break;
1246                 case CEE_NEWOBJ:
1247                         token = read32 (ip + 1);
1248                         /*
1249                          * FIXME: we could just load the signature ...
1250                          */
1251                         cmethod = mono_get_method (image, token, NULL);
1252                         if (!cmethod)
1253                                 ADD_INVALID (list, g_strdup_printf ("Constructor 0x%08x not found at 0x%04x", token, ip_offset));
1254                         csig = cmethod->signature;
1255                         CHECK_STACK_UNDERFLOW (csig->param_count);
1256                         cur_stack -= csig->param_count;
1257                         CHECK_STACK_OVERFLOW ();
1258                         ++cur_stack;
1259                         ip += 5;
1260                         break;
1261                 case CEE_CASTCLASS:
1262                 case CEE_ISINST:
1263                         token = read32 (ip + 1);
1264                         CHECK_STACK_UNDERFLOW (1);
1265                         ip += 5;
1266                         break;
1267                 case CEE_CONV_R_UN:
1268                         CHECK_STACK_UNDERFLOW (1);
1269                         ++ip;
1270                         break;
1271                 case CEE_UNUSED58:
1272                 case CEE_UNUSED1:
1273                         ++ip; /* warn, error ? */
1274                         break;
1275                 case CEE_UNBOX:
1276                         token = read32 (ip + 1);
1277                         CHECK_STACK_UNDERFLOW (1);
1278                         ip += 5;
1279                         break;
1280                 case CEE_THROW:
1281                         CHECK_STACK_UNDERFLOW (1);
1282                         --cur_stack;
1283                         ++ip;
1284                         break;
1285                 case CEE_LDFLD:
1286                         CHECK_STACK_UNDERFLOW (1);
1287                         token = read32 (ip + 1);
1288                         ip += 5;
1289                         break;
1290                 case CEE_LDFLDA:
1291                         CHECK_STACK_UNDERFLOW (1);
1292                         token = read32 (ip + 1);
1293                         ip += 5;
1294                         break;
1295                 case CEE_STFLD:
1296                         CHECK_STACK_UNDERFLOW (2);
1297                         cur_stack -= 2;
1298                         token = read32 (ip + 1);
1299                         ip += 5;
1300                         break;
1301                 case CEE_LDSFLD:
1302                         CHECK_STACK_OVERFLOW ();
1303                         token = read32 (ip + 1);
1304                         ++cur_stack;
1305                         ip += 5;
1306                         break;
1307                 case CEE_LDSFLDA:
1308                         CHECK_STACK_OVERFLOW ();
1309                         token = read32 (ip + 1);
1310                         ++cur_stack;
1311                         ip += 5;
1312                         break;
1313                 case CEE_STSFLD:
1314                         CHECK_STACK_UNDERFLOW (1);
1315                         --cur_stack;
1316                         token = read32 (ip + 1);
1317                         ip += 5;
1318                         break;
1319                 case CEE_STOBJ:
1320                         CHECK_STACK_UNDERFLOW (2);
1321                         cur_stack -= 2;
1322                         token = read32 (ip + 1);
1323                         ip += 5;
1324                         break;
1325                 case CEE_CONV_OVF_I1_UN:
1326                 case CEE_CONV_OVF_I2_UN:
1327                 case CEE_CONV_OVF_I4_UN:
1328                 case CEE_CONV_OVF_I8_UN:
1329                 case CEE_CONV_OVF_U1_UN:
1330                 case CEE_CONV_OVF_U2_UN:
1331                 case CEE_CONV_OVF_U4_UN:
1332                 case CEE_CONV_OVF_U8_UN:
1333                 case CEE_CONV_OVF_I_UN:
1334                 case CEE_CONV_OVF_U_UN:
1335                         CHECK_STACK_UNDERFLOW (1);
1336                         ++ip;
1337                         break;
1338                 case CEE_BOX:
1339                         CHECK_STACK_UNDERFLOW (1);
1340                         token = read32 (ip + 1);
1341                         ip += 5;
1342                         break;
1343                 case CEE_NEWARR:
1344                         CHECK_STACK_UNDERFLOW (1);
1345                         token = read32 (ip + 1);
1346                         ip += 5;
1347                         break;
1348                 case CEE_LDLEN:
1349                         CHECK_STACK_UNDERFLOW (1);
1350                         ++ip;
1351                         break;
1352                 case CEE_LDELEMA:
1353                         CHECK_STACK_UNDERFLOW (2);
1354                         --cur_stack;
1355                         token = read32 (ip + 1);
1356                         ip += 5;
1357                         break;
1358                 case CEE_LDELEM_I1:
1359                 case CEE_LDELEM_U1:
1360                 case CEE_LDELEM_I2:
1361                 case CEE_LDELEM_U2:
1362                 case CEE_LDELEM_I4:
1363                 case CEE_LDELEM_U4:
1364                 case CEE_LDELEM_I8:
1365                 case CEE_LDELEM_I:
1366                 case CEE_LDELEM_R4:
1367                 case CEE_LDELEM_R8:
1368                 case CEE_LDELEM_REF:
1369                         CHECK_STACK_UNDERFLOW (2);
1370                         --cur_stack;
1371                         ++ip;
1372                         break;
1373                 case CEE_STELEM_I:
1374                 case CEE_STELEM_I1:
1375                 case CEE_STELEM_I2:
1376                 case CEE_STELEM_I4:
1377                 case CEE_STELEM_I8:
1378                 case CEE_STELEM_R4:
1379                 case CEE_STELEM_R8:
1380                 case CEE_STELEM_REF:
1381                         CHECK_STACK_UNDERFLOW (3);
1382                         cur_stack -= 3;
1383                         ++ip;
1384                         break;
1385                 case CEE_UNUSED2:
1386                 case CEE_UNUSED3:
1387                 case CEE_UNUSED4:
1388                 case CEE_UNUSED5:
1389                 case CEE_UNUSED6:
1390                 case CEE_UNUSED7:
1391                 case CEE_UNUSED8:
1392                 case CEE_UNUSED9:
1393                 case CEE_UNUSED10:
1394                 case CEE_UNUSED11:
1395                 case CEE_UNUSED12:
1396                 case CEE_UNUSED13:
1397                 case CEE_UNUSED14:
1398                 case CEE_UNUSED15:
1399                 case CEE_UNUSED16:
1400                 case CEE_UNUSED17:
1401                         ++ip; /* warn, error ? */
1402                         break;
1403                 case CEE_CONV_OVF_I1:
1404                 case CEE_CONV_OVF_U1:
1405                 case CEE_CONV_OVF_I2:
1406                 case CEE_CONV_OVF_U2:
1407                 case CEE_CONV_OVF_I4:
1408                 case CEE_CONV_OVF_U4:
1409                 case CEE_CONV_OVF_I8:
1410                 case CEE_CONV_OVF_U8:
1411                         CHECK_STACK_UNDERFLOW (1);
1412                         ++ip;
1413                         break;
1414                 case CEE_UNUSED50:
1415                 case CEE_UNUSED18:
1416                 case CEE_UNUSED19:
1417                 case CEE_UNUSED20:
1418                 case CEE_UNUSED21:
1419                 case CEE_UNUSED22:
1420                 case CEE_UNUSED23:
1421                         ++ip; /* warn, error ? */
1422                         break;
1423                 case CEE_REFANYVAL:
1424                         CHECK_STACK_UNDERFLOW (1);
1425                         ++ip;
1426                         break;
1427                 case CEE_CKFINITE:
1428                         CHECK_STACK_UNDERFLOW (1);
1429                         ++ip;
1430                         break;
1431                 case CEE_UNUSED24:
1432                 case CEE_UNUSED25:
1433                         ++ip; /* warn, error ? */
1434                         break;
1435                 case CEE_MKREFANY:
1436                         CHECK_STACK_UNDERFLOW (1);
1437                         token = read32 (ip + 1);
1438                         ip += 5;
1439                         break;
1440                 case CEE_UNUSED59:
1441                 case CEE_UNUSED60:
1442                 case CEE_UNUSED61:
1443                 case CEE_UNUSED62:
1444                 case CEE_UNUSED63:
1445                 case CEE_UNUSED64:
1446                 case CEE_UNUSED65:
1447                 case CEE_UNUSED66:
1448                 case CEE_UNUSED67:
1449                         ++ip; /* warn, error ? */
1450                         break;
1451                 case CEE_LDTOKEN:
1452                         CHECK_STACK_OVERFLOW ();
1453                         token = read32 (ip + 1);
1454                         ++cur_stack;
1455                         ip += 5;
1456                         break;
1457                 case CEE_CONV_U2:
1458                 case CEE_CONV_U1:
1459                 case CEE_CONV_I:
1460                 case CEE_CONV_OVF_I:
1461                 case CEE_CONV_OVF_U:
1462                         CHECK_STACK_UNDERFLOW (1);
1463                         ++ip;
1464                         break;
1465                 case CEE_ADD_OVF:
1466                 case CEE_ADD_OVF_UN:
1467                 case CEE_MUL_OVF:
1468                 case CEE_MUL_OVF_UN:
1469                 case CEE_SUB_OVF:
1470                 case CEE_SUB_OVF_UN:
1471                         CHECK_STACK_UNDERFLOW (2);
1472                         --cur_stack;
1473                         ++ip;
1474                         break;
1475                 case CEE_ENDFINALLY:
1476                         ++ip;
1477                         start = 1;
1478                         break;
1479                 case CEE_LEAVE:
1480                         target = ip + (gint32)read32(ip + 1) + 5;
1481                         if (target >= end || target < header->code)
1482                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1483                         if (!is_correct_leave (header, ip_offset, target - header->code))
1484                                 ADD_INVALID (list, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ip_offset));
1485                         ip += 5;
1486                         start = 1;
1487                         break;
1488                 case CEE_LEAVE_S:
1489                         target = ip + (signed char)ip [1] + 2;
1490                         if (target >= end || target < header->code)
1491                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1492                         if (!is_correct_leave (header, ip_offset, target - header->code))
1493                                 ADD_INVALID (list, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ip_offset));
1494                         ip += 2;
1495                         start = 1;
1496                         break;
1497                 case CEE_STIND_I:
1498                         CHECK_STACK_UNDERFLOW (2);
1499                         cur_stack -= 2;
1500                         ++ip;
1501                         break;
1502                 case CEE_CONV_U:
1503                         CHECK_STACK_UNDERFLOW (1);
1504                         ++ip;
1505                         break;
1506                 case CEE_UNUSED26:
1507                 case CEE_UNUSED27:
1508                 case CEE_UNUSED28:
1509                 case CEE_UNUSED29:
1510                 case CEE_UNUSED30:
1511                 case CEE_UNUSED31:
1512                 case CEE_UNUSED32:
1513                 case CEE_UNUSED33:
1514                 case CEE_UNUSED34:
1515                 case CEE_UNUSED35:
1516                 case CEE_UNUSED36:
1517                 case CEE_UNUSED37:
1518                 case CEE_UNUSED38:
1519                 case CEE_UNUSED39:
1520                 case CEE_UNUSED40:
1521                 case CEE_UNUSED41:
1522                 case CEE_UNUSED42:
1523                 case CEE_UNUSED43:
1524                 case CEE_UNUSED44:
1525                 case CEE_UNUSED45:
1526                 case CEE_UNUSED46:
1527                 case CEE_UNUSED47:
1528                 case CEE_UNUSED48:
1529                         ++ip;
1530                         break;
1531                 case CEE_PREFIX7:
1532                 case CEE_PREFIX6:
1533                 case CEE_PREFIX5:
1534                 case CEE_PREFIX4:
1535                 case CEE_PREFIX3:
1536                 case CEE_PREFIX2:
1537                 case CEE_PREFIXREF:
1538                         ++ip;
1539                         break;
1540                 case CEE_PREFIX1:
1541                         ++ip;
1542                         switch (*ip) {
1543                         case CEE_ARGLIST:
1544                                 CHECK_STACK_OVERFLOW ();
1545                                 ++ip;
1546                                 break;
1547                         case CEE_CEQ:
1548                         case CEE_CGT:
1549                         case CEE_CGT_UN:
1550                         case CEE_CLT:
1551                         case CEE_CLT_UN:
1552                                 CHECK_STACK_UNDERFLOW (2);
1553                                 --cur_stack;
1554                                 ++ip;
1555                                 break;
1556                         case CEE_LDFTN:
1557                                 CHECK_STACK_OVERFLOW ();
1558                                 token = read32 (ip + 1);
1559                                 ip += 5;
1560                                 break;
1561                         case CEE_LDVIRTFTN:
1562                                 CHECK_STACK_UNDERFLOW (1);
1563                                 token = read32 (ip + 1);
1564                                 ip += 5;
1565                                 break;
1566                         case CEE_UNUSED56:
1567                                 ++ip;
1568                                 break;
1569                         case CEE_LDARG:
1570                         case CEE_LDARGA:
1571                                 if (read16 (ip + 1) >= max_args)
1572                                         ADD_INVALID (list, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", read16 (ip + 1), ip_offset));
1573                                 CHECK_STACK_OVERFLOW ();
1574                                 ++cur_stack;
1575                                 ip += 3;
1576                                 break;
1577                         case CEE_STARG:
1578                                 if (read16 (ip + 1) >= max_args)
1579                                         ADD_INVALID (list, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", read16(ip + 1), ip_offset));
1580                                 CHECK_STACK_UNDERFLOW (1);
1581                                 --cur_stack;
1582                                 ip += 3;
1583                                 break;
1584                         case CEE_LDLOC:
1585                         case CEE_LDLOCA:
1586                                 if (read16 (ip + 1) >= header->num_locals)
1587                                         ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", read16 (ip + 1), ip_offset));
1588                                 /* no need to check if the var is initialized if the address is taken */
1589                                 if (*ip == CEE_LDLOC && !local_state [read16 (ip + 1)])
1590                                         ADD_INVALID (list, g_strdup_printf ("Local var %d is initialized at 0x%04x", read16 (ip + 1), ip_offset));
1591                                 CHECK_STACK_OVERFLOW ();
1592                                 ++cur_stack;
1593                                 ip += 3;
1594                                 break;
1595                         case CEE_STLOC:
1596                                 if (read16 (ip + 1) >= header->num_locals)
1597                                         ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", read16 (ip + 1), ip_offset));
1598                                 local_state [read16 (ip + 1)] = 1;
1599                                 CHECK_STACK_UNDERFLOW (1);
1600                                 --cur_stack;
1601                                 ip += 3;
1602                                 break;
1603                         case CEE_LOCALLOC:
1604                                 if (cur_stack != 1)
1605                                         ADD_INVALID (list, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ip_offset));
1606                                 ++ip;
1607                                 break;
1608                         case CEE_UNUSED57:
1609                                 ++ip;
1610                                 break;
1611                         case CEE_ENDFILTER:
1612                                 if (cur_stack != 1)
1613                                         ADD_INVALID (list, g_strdup_printf ("Stack must have only filter result in endfilter at 0x%04x", ip_offset));
1614                                 ++ip;
1615                                 break;
1616                         case CEE_UNALIGNED_:
1617                                 prefix |= PREFIX_UNALIGNED;
1618                                 ++ip;
1619                                 break;
1620                         case CEE_VOLATILE_:
1621                                 prefix |= PREFIX_VOLATILE;
1622                                 ++ip;
1623                                 break;
1624                         case CEE_TAIL_:
1625                                 prefix |= PREFIX_TAIL;
1626                                 ++ip;
1627                                 if (ip < end && (*ip != CEE_CALL && *ip != CEE_CALLI && *ip != CEE_CALLVIRT))
1628                                         ADD_INVALID (list, g_strdup_printf ("tail prefix must be used only with call opcodes at 0x%04x", ip_offset));
1629                                 break;
1630                         case CEE_INITOBJ:
1631                                 CHECK_STACK_UNDERFLOW (1);
1632                                 token = read32 (ip + 1);
1633                                 ip += 5;
1634                                 break;
1635                         case CEE_UNUSED68:
1636                                 ++ip;
1637                                 break;
1638                         case CEE_CPBLK:
1639                                 CHECK_STACK_UNDERFLOW (3);
1640                                 ip++;
1641                                 break;
1642                         case CEE_INITBLK:
1643                                 CHECK_STACK_UNDERFLOW (3);
1644                                 ip++;
1645                                 break;
1646                         case CEE_UNUSED69:
1647                                 ++ip;
1648                                 break;
1649                         case CEE_RETHROW:
1650                                 ++ip;
1651                                 break;
1652                         case CEE_UNUSED:
1653                                 ++ip;
1654                                 break;
1655                         case CEE_SIZEOF:
1656                                 CHECK_STACK_OVERFLOW ();
1657                                 token = read32 (ip + 1);
1658                                 ip += 5;
1659                                 break;
1660                         case CEE_REFANYTYPE:
1661                                 CHECK_STACK_UNDERFLOW (1);
1662                                 ++ip;
1663                                 break;
1664                         case CEE_UNUSED52:
1665                         case CEE_UNUSED53:
1666                         case CEE_UNUSED54:
1667                         case CEE_UNUSED55:
1668                         case CEE_UNUSED70:
1669                                 ++ip;
1670                                 break;
1671                         }
1672                 }
1673         }
1674         /*
1675          * FIXME: if ip != end we overflowed: mark as error.
1676          */
1677 invalid_cil:
1678
1679         g_free (local_state);
1680         g_free (code);
1681         return list;
1682 }