New test.
[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 void
30 mono_free_verify_list (GSList *list)
31 {
32         MonoVerifyInfo* info;
33         GSList *tmp;
34
35         for (tmp = list; tmp; tmp = tmp->next) {
36                 info = tmp->data;
37                 g_free (info->message);
38                 g_free (info);
39         }
40         g_slist_free (list);
41 }
42
43 #define ADD_ERROR(list,msg)     \
44         do {    \
45                 MonoVerifyInfo *vinfo = g_new (MonoVerifyInfo, 1);      \
46                 vinfo->status = MONO_VERIFY_ERROR;      \
47                 vinfo->message = (msg); \
48                 (list) = g_slist_prepend ((list), vinfo);       \
49         } while (0)
50
51 #define ADD_WARN(list,code,msg) \
52         do {    \
53                 MonoVerifyInfo *vinfo = g_new (MonoVerifyInfo, 1);      \
54                 vinfo->status = (code); \
55                 vinfo->message = (msg); \
56                 (list) = g_slist_prepend ((list), vinfo);       \
57         } while (0)
58
59 static const char
60 valid_cultures[][9] = {
61         "ar-SA", "ar-IQ", "ar-EG", "ar-LY",
62         "ar-DZ", "ar-MA", "ar-TN", "ar-OM",
63         "ar-YE", "ar-SY", "ar-JO", "ar-LB",
64         "ar-KW", "ar-AE", "ar-BH", "ar-QA",
65         "bg-BG", "ca-ES", "zh-TW", "zh-CN",
66         "zh-HK", "zh-SG", "zh-MO", "cs-CZ",
67         "da-DK", "de-DE", "de-CH", "de-AT",
68         "de-LU", "de-LI", "el-GR", "en-US",
69         "en-GB", "en-AU", "en-CA", "en-NZ",
70         "en-IE", "en-ZA", "en-JM", "en-CB",
71         "en-BZ", "en-TT", "en-ZW", "en-PH",
72         "es-ES-Ts", "es-MX", "es-ES-Is", "es-GT",
73         "es-CR", "es-PA", "es-DO", "es-VE",
74         "es-CO", "es-PE", "es-AR", "es-EC",
75         "es-CL", "es-UY", "es-PY", "es-BO",
76         "es-SV", "es-HN", "es-NI", "es-PR",
77         "Fi-FI", "fr-FR", "fr-BE", "fr-CA",
78         "Fr-CH", "fr-LU", "fr-MC", "he-IL",
79         "hu-HU", "is-IS", "it-IT", "it-CH",
80         "Ja-JP", "ko-KR", "nl-NL", "nl-BE",
81         "nb-NO", "nn-NO", "pl-PL", "pt-BR",
82         "pt-PT", "ro-RO", "ru-RU", "hr-HR",
83         "Lt-sr-SP", "Cy-sr-SP", "sk-SK", "sq-AL",
84         "sv-SE", "sv-FI", "th-TH", "tr-TR",
85         "ur-PK", "id-ID", "uk-UA", "be-BY",
86         "sl-SI", "et-EE", "lv-LV", "lt-LT",
87         "fa-IR", "vi-VN", "hy-AM", "Lt-az-AZ",
88         "Cy-az-AZ",
89         "eu-ES", "mk-MK", "af-ZA",
90         "ka-GE", "fo-FO", "hi-IN", "ms-MY",
91         "ms-BN", "kk-KZ", "ky-KZ", "sw-KE",
92         "Lt-uz-UZ", "Cy-uz-UZ", "tt-TA", "pa-IN",
93         "gu-IN", "ta-IN", "te-IN", "kn-IN",
94         "mr-IN", "sa-IN", "mn-MN", "gl-ES",
95         "kok-IN", "syr-SY", "div-MV"
96 };
97
98 static int
99 is_valid_culture (const char *cname)
100 {
101         int i;
102         int found;
103                         
104         found = *cname == 0;
105         for (i = 0; i < G_N_ELEMENTS (valid_cultures); ++i) {
106                 if (g_strcasecmp (valid_cultures [i], cname)) {
107                         found = 1;
108                         break;
109                 }
110         }
111         return found;
112 }
113
114 static int
115 is_valid_assembly_flags (guint32 flags) {
116         /* Metadata: 22.1.2 */
117         flags &= ~(0x8000 | 0x4000); /* ignore reserved bits 0x0030? */
118         return ((flags == 1) || (flags == 0));
119 }
120
121 static int
122 is_valid_blob (MonoImage *image, guint32 blob_index, int notnull)
123 {
124         guint32 size;
125         const char *p, *blob_end;
126         
127         if (blob_index >= image->heap_blob.size)
128                 return 0;
129         p = mono_metadata_blob_heap (image, blob_index);
130         size = mono_metadata_decode_blob_size (p, &blob_end);
131         if (blob_index + size + (blob_end-p) > image->heap_blob.size)
132                 return 0;
133         if (notnull && !size)
134                 return 0;
135         return 1;
136 }
137
138 static const char*
139 is_valid_string (MonoImage *image, guint32 str_index, int notnull)
140 {
141         const char *p, *blob_end, *res;
142         
143         if (str_index >= image->heap_strings.size)
144                 return NULL;
145         res = p = mono_metadata_string_heap (image, str_index);
146         blob_end = mono_metadata_string_heap (image, image->heap_strings.size - 1);
147         if (notnull && !*p)
148                 return 0;
149         /* 
150          * FIXME: should check it's a valid utf8 string, too.
151          */
152         while (p <= blob_end) {
153                 if (!*p)
154                         return res;
155                 ++p;
156         }
157         return *p? NULL: res;
158 }
159
160 static int
161 is_valid_cls_ident (const char *p)
162 {
163         /*
164          * FIXME: we need the full unicode glib support for this.
165          * Check: http://www.unicode.org/unicode/reports/tr15/Identifier.java
166          * We do the lame thing for now.
167          */
168         if (!isalpha (*p))
169                 return 0;
170         ++p;
171         while (*p) {
172                 if (!isalnum (*p) && *p != '_')
173                         return 0;
174                 ++p;
175         }
176         return 1;
177 }
178
179 static int
180 is_valid_filename (const char *p)
181 {
182         if (!*p)
183                 return 0;
184         return strpbrk (p, "\\//:")? 0: 1;
185 }
186
187 static GSList*
188 verify_assembly_table (MonoImage *image, GSList *list, int level)
189 {
190         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
191         guint32 cols [MONO_ASSEMBLY_SIZE];
192         const char *p;
193
194         if (level & MONO_VERIFY_ERROR) {
195                 if (t->rows > 1)
196                         ADD_ERROR (list, g_strdup ("Assembly table may only have 0 or 1 rows"));
197                 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
198                 
199                 switch (cols [MONO_ASSEMBLY_HASH_ALG]) {
200                 case ASSEMBLY_HASH_NONE:
201                 case ASSEMBLY_HASH_MD5:
202                 case ASSEMBLY_HASH_SHA1:
203                         break;
204                 default:
205                         ADD_ERROR (list, g_strdup_printf ("Hash algorithm 0x%x unknown", cols [MONO_ASSEMBLY_HASH_ALG]));
206                 }
207                 
208                 if (!is_valid_assembly_flags (cols [MONO_ASSEMBLY_FLAGS]))
209                         ADD_ERROR (list, g_strdup_printf ("Invalid flags in assembly: 0x%x", cols [MONO_ASSEMBLY_FLAGS]));
210                 
211                 if (!is_valid_blob (image, cols [MONO_ASSEMBLY_PUBLIC_KEY], FALSE))
212                         ADD_ERROR (list, g_strdup ("Assembly public key is an invalid index"));
213                 
214                 if (!(p = is_valid_string (image, cols [MONO_ASSEMBLY_NAME], TRUE))) {
215                         ADD_ERROR (list, g_strdup ("Assembly name is invalid"));
216                 } else {
217                         if (strpbrk (p, ":\\/."))
218                                 ADD_ERROR (list, g_strdup_printf ("Assembly name `%s' contains invalid chars", p));
219                 }
220
221                 if (!(p = is_valid_string (image, cols [MONO_ASSEMBLY_CULTURE], FALSE))) {
222                         ADD_ERROR (list, g_strdup ("Assembly culture is an invalid index"));
223                 } else {
224                         if (!is_valid_culture (p))
225                                 ADD_ERROR (list, g_strdup_printf ("Assembly culture `%s' is invalid", p));
226                 }
227         }
228         return list;
229 }
230
231 static GSList*
232 verify_assemblyref_table (MonoImage *image, GSList *list, int level)
233 {
234         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
235         guint32 cols [MONO_ASSEMBLYREF_SIZE];
236         const char *p;
237         int i;
238
239         if (level & MONO_VERIFY_ERROR) {
240                 for (i = 0; i < t->rows; ++i) {
241                         mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
242                         if (!is_valid_assembly_flags (cols [MONO_ASSEMBLYREF_FLAGS]))
243                                 ADD_ERROR (list, g_strdup_printf ("Invalid flags in assemblyref row %d: 0x%x", i + 1, cols [MONO_ASSEMBLY_FLAGS]));
244                 
245                         if (!is_valid_blob (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], FALSE))
246                                 ADD_ERROR (list, g_strdup_printf ("AssemblyRef public key in row %d is an invalid index", i + 1));
247                 
248                         if (!(p = is_valid_string (image, cols [MONO_ASSEMBLYREF_CULTURE], FALSE))) {
249                                 ADD_ERROR (list, g_strdup_printf ("AssemblyRef culture in row %d is invalid", i + 1));
250                         } else {
251                                 if (!is_valid_culture (p))
252                                         ADD_ERROR (list, g_strdup_printf ("AssemblyRef culture `%s' in row %d is invalid", p, i + 1));
253                         }
254
255                         if (cols [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob (image, cols [MONO_ASSEMBLYREF_HASH_VALUE], TRUE))
256                                 ADD_ERROR (list, g_strdup_printf ("AssemblyRef hash value in row %d is invalid or not null and empty", i + 1));
257                 }
258         }
259         if (level & MONO_VERIFY_WARNING) {
260                 /* check for duplicated rows */
261                 for (i = 0; i < t->rows; ++i) {
262                 }
263         }
264         return list;
265 }
266
267 static GSList*
268 verify_class_layout_table (MonoImage *image, GSList *list, int level)
269 {
270         MonoTableInfo *t = &image->tables [MONO_TABLE_CLASSLAYOUT];
271         MonoTableInfo *tdef = &image->tables [MONO_TABLE_TYPEDEF];
272         guint32 cols [MONO_CLASS_LAYOUT_SIZE];
273         guint32 value, i;
274         
275         if (level & MONO_VERIFY_ERROR) {
276                 for (i = 0; i < t->rows; ++i) {
277                         mono_metadata_decode_row (t, i, cols, MONO_CLASS_LAYOUT_SIZE);
278
279                         if (cols [MONO_CLASS_LAYOUT_PARENT] > tdef->rows || !cols [MONO_CLASS_LAYOUT_PARENT]) {
280                                 ADD_ERROR (list, g_strdup_printf ("Parent in class layout is invalid in row %d", i + 1));
281                         } else {
282                                 value = mono_metadata_decode_row_col (tdef, cols [MONO_CLASS_LAYOUT_PARENT] - 1, MONO_TYPEDEF_FLAGS);
283                                 if (value & TYPE_ATTRIBUTE_INTERFACE)
284                                         ADD_ERROR (list, g_strdup_printf ("Parent in class layout row %d is an interface", i + 1));
285                                 if (value & TYPE_ATTRIBUTE_AUTO_LAYOUT)
286                                         ADD_ERROR (list, g_strdup_printf ("Parent in class layout row %d is AutoLayout", i + 1));
287                                 if (value & TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT) {
288                                         switch (cols [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
289                                         case 0: case 1: case 2: case 4: case 8: case 16:
290                                         case 32: case 64: case 128: break;
291                                         default:
292                                                 ADD_ERROR (list, g_strdup_printf ("Packing size %d in class layout row %d is invalid", cols [MONO_CLASS_LAYOUT_PACKING_SIZE], i + 1));
293                                         }
294                                 } else if (value & TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
295                                         /*
296                                          * FIXME: LAMESPEC: it claims it must be 0 (it's 1, instead).
297                                         if (cols [MONO_CLASS_LAYOUT_PACKING_SIZE])
298                                                 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));
299                                         */
300                                 }
301                                 /*
302                                  * FIXME: we need to check that if class size != 0, 
303                                  * it needs to be greater than the class calculated size.
304                                  * If parent is a valuetype it also needs to be smaller than
305                                  * 1 MByte (0x100000 bytes).
306                                  * To do both these checks we need to load the referenced 
307                                  * assemblies, though (the spec claims we didn't have to, bah).
308                                  */
309                                 /* 
310                                  * We need to check that the parent types have the samme layout 
311                                  * type as well.
312                                  */
313                         }
314                 }
315         }
316         
317         return list;
318 }
319
320 static GSList*
321 verify_constant_table (MonoImage *image, GSList *list, int level)
322 {
323         MonoTableInfo *t = &image->tables [MONO_TABLE_CONSTANT];
324         guint32 cols [MONO_CONSTANT_SIZE];
325         guint32 value, i;
326         GHashTable *dups = g_hash_table_new (NULL, NULL);
327         
328         for (i = 0; i < t->rows; ++i) {
329                 mono_metadata_decode_row (t, i, cols, MONO_CONSTANT_SIZE);
330
331                 if (level & MONO_VERIFY_ERROR)
332                         if (g_hash_table_lookup (dups, GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT])))
333                                 ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is duplicated in Constant row %d", cols [MONO_CONSTANT_PARENT], i + 1));
334                 g_hash_table_insert (dups, GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT]),
335                                 GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT]));
336
337                 switch (cols [MONO_CONSTANT_TYPE]) {
338                 case MONO_TYPE_U1: /* LAMESPEC: it says I1...*/
339                 case MONO_TYPE_U2:
340                 case MONO_TYPE_U4:
341                 case MONO_TYPE_U8:
342                         if (level & MONO_VERIFY_CLS)
343                                 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));
344                 case MONO_TYPE_BOOLEAN:
345                 case MONO_TYPE_CHAR:
346                 case MONO_TYPE_I1:
347                 case MONO_TYPE_I2:
348                 case MONO_TYPE_I4:
349                 case MONO_TYPE_I8:
350                 case MONO_TYPE_R4:
351                 case MONO_TYPE_R8:
352                 case MONO_TYPE_STRING:
353                 case MONO_TYPE_CLASS:
354                         break;
355                 default:
356                         if (level & MONO_VERIFY_ERROR)
357                                 ADD_ERROR (list, g_strdup_printf ("Type 0x%x is invalid in Constant row %d", cols [MONO_CONSTANT_TYPE], i + 1));
358                 }
359                 if (level & MONO_VERIFY_ERROR) {
360                         value = cols [MONO_CONSTANT_PARENT] >> MONO_HASCONSTANT_BITS;
361                         switch (cols [MONO_CONSTANT_PARENT] & MONO_HASCONSTANT_MASK) {
362                         case MONO_HASCONSTANT_FIEDDEF:
363                                 if (value > image->tables [MONO_TABLE_FIELD].rows)
364                                         ADD_ERROR (list, g_strdup_printf ("Parent (field) is invalid in Constant row %d", i + 1));
365                                 break;
366                         case MONO_HASCONSTANT_PARAM:
367                                 if (value > image->tables [MONO_TABLE_PARAM].rows)
368                                         ADD_ERROR (list, g_strdup_printf ("Parent (param) is invalid in Constant row %d", i + 1));
369                                 break;
370                         case MONO_HASCONSTANT_PROPERTY:
371                                 if (value > image->tables [MONO_TABLE_PROPERTY].rows)
372                                         ADD_ERROR (list, g_strdup_printf ("Parent (property) is invalid in Constant row %d", i + 1));
373                                 break;
374                         default:
375                                 ADD_ERROR (list, g_strdup_printf ("Parent is invalid in Constant row %d", i + 1));
376                                 break;
377                         }
378                 }
379                 if (level & MONO_VERIFY_CLS) {
380                         /* 
381                          * FIXME: verify types is consistent with the enum type
382                          * is parent is an enum.
383                          */
384                 }
385         }
386         g_hash_table_destroy (dups);
387         return list;
388 }
389
390 static GSList*
391 verify_event_map_table (MonoImage *image, GSList *list, int level)
392 {
393         MonoTableInfo *t = &image->tables [MONO_TABLE_EVENTMAP];
394         guint32 cols [MONO_EVENT_MAP_SIZE];
395         guint32 i, last_event;
396         GHashTable *dups = g_hash_table_new (NULL, NULL);
397
398         last_event = 0;
399
400         for (i = 0; i < t->rows; ++i) {
401                 mono_metadata_decode_row (t, i, cols, MONO_EVENT_MAP_SIZE);
402                 if (level & MONO_VERIFY_ERROR)
403                         if (g_hash_table_lookup (dups, GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT])))
404                                 ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is duplicated in Event Map row %d", cols [MONO_EVENT_MAP_PARENT], i + 1));
405                 g_hash_table_insert (dups, GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT]),
406                                 GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT]));
407                 if (level & MONO_VERIFY_ERROR) {
408                         if (cols [MONO_EVENT_MAP_PARENT] > image->tables [MONO_TABLE_TYPEDEF].rows)
409                                 ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is invalid in Event Map row %d", cols [MONO_EVENT_MAP_PARENT], i + 1));
410                         if (cols [MONO_EVENT_MAP_EVENTLIST] > image->tables [MONO_TABLE_EVENT].rows)
411                                 ADD_ERROR (list, g_strdup_printf ("EventList 0x%08x is invalid in Event Map row %d", cols [MONO_EVENT_MAP_EVENTLIST], i + 1));
412
413                         if (cols [MONO_EVENT_MAP_EVENTLIST] <= last_event)
414                                 ADD_ERROR (list, g_strdup_printf ("EventList overlap in Event Map row %d", i + 1));
415                         last_event = cols [MONO_EVENT_MAP_EVENTLIST];
416                 }
417         }
418
419         g_hash_table_destroy (dups);
420         return list;
421 }
422
423 static GSList*
424 verify_event_table (MonoImage *image, GSList *list, int level)
425 {
426         MonoTableInfo *t = &image->tables [MONO_TABLE_EVENT];
427         guint32 cols [MONO_EVENT_SIZE];
428         const char *p;
429         guint32 value, i;
430         
431         for (i = 0; i < t->rows; ++i) {
432                 mono_metadata_decode_row (t, i, cols, MONO_EVENT_SIZE);
433
434                 if (cols [MONO_EVENT_FLAGS] & ~(EVENT_SPECIALNAME|EVENT_RTSPECIALNAME)) {
435                         if (level & MONO_VERIFY_ERROR)
436                                 ADD_ERROR (list, g_strdup_printf ("Flags 0x%04x invalid in Event row %d", cols [MONO_EVENT_FLAGS], i + 1));
437                 }
438                 if (!(p = is_valid_string (image, cols [MONO_EVENT_NAME], TRUE))) {
439                         if (level & MONO_VERIFY_ERROR)
440                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in Event row %d", i + 1));
441                 } else {
442                         if (level & MONO_VERIFY_CLS) {
443                                 if (!is_valid_cls_ident (p))
444                                         ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Invalid CLS name '%s` in Event row %d", p, i + 1));
445                         }
446                 }
447                 
448                 if (level & MONO_VERIFY_ERROR && cols [MONO_EVENT_TYPE]) {
449                         value = cols [MONO_EVENT_TYPE] >> MONO_TYPEDEFORREF_BITS;
450                         switch (cols [MONO_EVENT_TYPE] & MONO_TYPEDEFORREF_MASK) {
451                         case MONO_TYPEDEFORREF_TYPEDEF:
452                                 if (!value || value > image->tables [MONO_TABLE_TYPEDEF].rows)
453                                         ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
454                                 break;
455                         case MONO_TYPEDEFORREF_TYPEREF:
456                                 if (!value || value > image->tables [MONO_TABLE_TYPEREF].rows)
457                                         ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
458                                 break;
459                         case MONO_TYPEDEFORREF_TYPESPEC:
460                                 if (!value || value > image->tables [MONO_TABLE_TYPESPEC].rows)
461                                         ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
462                                 break;
463                         default:
464                                 ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
465                         }
466                 }
467                 /*
468                  * FIXME: check that there is 1 add and remove row in methodsemantics
469                  * and 0 or 1 raise and 0 or more other (maybe it's better to check for 
470                  * these while checking methodsemantics).
471                  * check for duplicated names for the same type [ERROR]
472                  * check for CLS duplicate names for the same type [CLS]
473                  */
474         }
475         return list;
476 }
477
478 static GSList*
479 verify_field_table (MonoImage *image, GSList *list, int level)
480 {
481         MonoTableInfo *t = &image->tables [MONO_TABLE_FIELD];
482         guint32 cols [MONO_FIELD_SIZE];
483         const char *p;
484         guint32 i, flags;
485         
486         for (i = 0; i < t->rows; ++i) {
487                 mono_metadata_decode_row (t, i, cols, MONO_FIELD_SIZE);
488                 /*
489                  * Check this field has only one owner and that the owner is not 
490                  * an interface (done in verify_typedef_table() )
491                  */
492                 flags = cols [MONO_FIELD_FLAGS];
493                 switch (flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) {
494                 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
495                 case FIELD_ATTRIBUTE_PRIVATE:
496                 case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
497                 case FIELD_ATTRIBUTE_ASSEMBLY:
498                 case FIELD_ATTRIBUTE_FAMILY:
499                 case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
500                 case FIELD_ATTRIBUTE_PUBLIC:
501                         break;
502                 default:
503                         if (level & MONO_VERIFY_ERROR)
504                                 ADD_ERROR (list, g_strdup_printf ("Invalid access mask in Field row %d", i + 1));
505                         break;
506                 }
507                 if (level & MONO_VERIFY_ERROR) {
508                         if ((flags & FIELD_ATTRIBUTE_LITERAL) && (flags & FIELD_ATTRIBUTE_INIT_ONLY))
509                                 ADD_ERROR (list, g_strdup_printf ("Literal and InitOnly cannot be both set in Field row %d", i + 1));
510                         if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
511                                 ADD_ERROR (list, g_strdup_printf ("Literal needs also Static set in Field row %d", i + 1));
512                         if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
513                                 ADD_ERROR (list, g_strdup_printf ("RTSpecialName needs also SpecialName set in Field row %d", i + 1));
514                         /*
515                          * FIXME: check there is only ono owner in the respective table.
516                          * if (flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
517                          * if (flags & FIELD_ATTRIBUTE_HAS_DEFAULT)
518                          * if (flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA)
519                          */
520                 }
521                 if (!(p = is_valid_string (image, cols [MONO_FIELD_NAME], TRUE))) {
522                         if (level & MONO_VERIFY_ERROR)
523                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in Field row %d", i + 1));
524                 } else {
525                         if (level & MONO_VERIFY_CLS) {
526                                 if (!is_valid_cls_ident (p))
527                                         ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Invalid CLS name '%s` in Field row %d", p, i + 1));
528                         }
529                 }
530                 /*
531                  * check signature.
532                  * if owner is module needs to be static, access mask needs to be compilercontrolled,
533                  * public or private (not allowed in cls mode).
534                  * if owner is an enum ...
535                  */
536                 
537                 
538         }
539         return list;
540 }
541
542 static GSList*
543 verify_file_table (MonoImage *image, GSList *list, int level)
544 {
545         MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
546         guint32 cols [MONO_FILE_SIZE];
547         const char *p;
548         guint32 i;
549         GHashTable *dups = g_hash_table_new (g_str_hash, g_str_equal);
550         
551         for (i = 0; i < t->rows; ++i) {
552                 mono_metadata_decode_row (t, i, cols, MONO_FILE_SIZE);
553                 if (level & MONO_VERIFY_ERROR) {
554                         if (cols [MONO_FILE_FLAGS] != FILE_CONTAINS_METADATA && cols [MONO_FILE_FLAGS] != FILE_CONTAINS_NO_METADATA)
555                                 ADD_ERROR (list, g_strdup_printf ("Invalid flags in File row %d", i + 1));
556                         if (!is_valid_blob (image, cols [MONO_FILE_HASH_VALUE], TRUE))
557                                 ADD_ERROR (list, g_strdup_printf ("File hash value in row %d is invalid or not null and empty", i + 1));
558                 }
559                 if (!(p = is_valid_string (image, cols [MONO_FILE_NAME], TRUE))) {
560                         if (level & MONO_VERIFY_ERROR)
561                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in File row %d", i + 1));
562                 } else {
563                         if (level & MONO_VERIFY_ERROR) {
564                                 if (!is_valid_filename (p))
565                                         ADD_ERROR (list, g_strdup_printf ("Invalid name '%s` in File row %d", p, i + 1));
566                                 else if (g_hash_table_lookup (dups, p)) {
567                                         ADD_ERROR (list, g_strdup_printf ("Duplicate name '%s` in File row %d", p, i + 1));
568                                 }
569                                 g_hash_table_insert (dups, (gpointer)p, (gpointer)p);
570                         }
571                 }
572                 /*
573                  * FIXME: I don't understand what this means:
574                  * If this module contains a row in the Assembly table (that is, if this module "holds the manifest") 
575                  * then there shall not be any row in the File table for this module - i.e., no self-reference  [ERROR]
576                  */
577
578         }
579         if (level & MONO_VERIFY_WARNING) {
580                 if (!t->rows && image->tables [MONO_TABLE_EXPORTEDTYPE].rows)
581                         ADD_WARN (list, MONO_VERIFY_WARNING, g_strdup ("ExportedType table should be empty if File table is empty"));
582         }
583         g_hash_table_destroy (dups);
584         return list;
585 }
586
587 static GSList*
588 verify_moduleref_table (MonoImage *image, GSList *list, int level)
589 {
590         MonoTableInfo *t = &image->tables [MONO_TABLE_MODULEREF];
591         MonoTableInfo *tfile = &image->tables [MONO_TABLE_FILE];
592         guint32 cols [MONO_MODULEREF_SIZE];
593         const char *p, *pf;
594         guint32 found, i, j, value;
595         GHashTable *dups = g_hash_table_new (g_str_hash, g_str_equal);
596         
597         for (i = 0; i < t->rows; ++i) {
598                 mono_metadata_decode_row (t, i, cols, MONO_MODULEREF_SIZE);
599                 if (!(p = is_valid_string (image, cols [MONO_MODULEREF_NAME], TRUE))) {
600                         if (level & MONO_VERIFY_ERROR)
601                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in ModuleRef row %d", i + 1));
602                 } else {
603                         if (level & MONO_VERIFY_ERROR) {
604                                 if (!is_valid_filename (p))
605                                         ADD_ERROR (list, g_strdup_printf ("Invalid name '%s` in ModuleRef row %d", p, i + 1));
606                                 else if (g_hash_table_lookup (dups, p)) {
607                                         ADD_WARN (list, MONO_VERIFY_WARNING, g_strdup_printf ("Duplicate name '%s` in ModuleRef row %d", p, i + 1));
608                                         g_hash_table_insert (dups, (gpointer)p, (gpointer)p);
609                                         found = 0;
610                                         for (j = 0; j < tfile->rows; ++j) {
611                                                 value = mono_metadata_decode_row_col (tfile, j, MONO_FILE_NAME);
612                                                 if ((pf = is_valid_string (image, value, TRUE)))
613                                                         if (strcmp (p, pf) == 0) {
614                                                                 found = 1;
615                                                                 break;
616                                                         }
617                                         }
618                                         if (!found)
619                                                 ADD_ERROR (list, g_strdup_printf ("Name '%s` in ModuleRef row %d doesn't have a match in File table", p, i + 1));
620                                 }
621                         }
622                 }
623         }
624         g_hash_table_destroy (dups);
625         return list;
626 }
627
628 static GSList*
629 verify_standalonesig_table (MonoImage *image, GSList *list, int level)
630 {
631         MonoTableInfo *t = &image->tables [MONO_TABLE_STANDALONESIG];
632         guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE];
633         const char *p;
634         guint32 i;
635
636         for (i = 0; i < t->rows; ++i) {
637                 mono_metadata_decode_row (t, i, cols, MONO_STAND_ALONE_SIGNATURE_SIZE);
638                 if (level & MONO_VERIFY_ERROR) {
639                         if (!is_valid_blob (image, cols [MONO_STAND_ALONE_SIGNATURE], TRUE)) {
640                                 ADD_ERROR (list, g_strdup_printf ("Signature is invalid in StandAloneSig row %d", i + 1));
641                         } else {
642                                 p = mono_metadata_blob_heap (image, cols [MONO_STAND_ALONE_SIGNATURE]);
643                                 /* FIXME: check it's a valid locals or method sig.*/
644                         }
645                 }
646         }
647         return list;
648 }
649
650 GSList*
651 mono_image_verify_tables (MonoImage *image, int level)
652 {
653         GSList *error_list = NULL;
654
655         error_list = verify_assembly_table (image, error_list, level);
656         /* 
657          * AssemblyOS, AssemblyProcessor, AssemblyRefOs and
658          * AssemblyRefProcessor should be ignored, 
659          * though we may want to emit a warning, since it should not 
660          * be present in a PE file.
661          */
662         error_list = verify_assemblyref_table (image, error_list, level);
663         error_list = verify_class_layout_table (image, error_list, level);
664         error_list = verify_constant_table (image, error_list, level);
665         /*
666          * cutom attribute, declsecurity 
667          */
668         error_list = verify_event_map_table (image, error_list, level);
669         error_list = verify_event_table (image, error_list, level);
670         error_list = verify_field_table (image, error_list, level);
671         error_list = verify_file_table (image, error_list, level);
672         error_list = verify_moduleref_table (image, error_list, level);
673         error_list = verify_standalonesig_table (image, error_list, level);
674
675         return g_slist_reverse (error_list);
676 }
677
678 enum {
679         TYPE_INV = 0, /* leave at 0. */
680         TYPE_I4  = 1,
681         TYPE_I8  = 2,
682         TYPE_PTR = 3,
683         TYPE_R8  = 4,
684         TYPE_MP  = 5,
685         TYPE_OBJ = 6,
686         TYPE_VT  = 7,
687         TYPE_MAX = 8
688 };
689
690 static const char*  const
691 arg_name [TYPE_MAX] = {
692         "Invalid",
693         "Int32",
694         "Int64",
695         "IntPtr",
696         "Double",
697         "Managed Pointer",
698         "ObjRef",
699         "ValueType"
700 };
701
702 static const char
703 bin_num_table [TYPE_MAX] [TYPE_MAX] = {
704         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
705         {TYPE_INV, TYPE_I4,  TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_MP,  TYPE_INV, TYPE_INV},
706         {TYPE_INV, TYPE_INV, TYPE_I8,  TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
707         {TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_MP,  TYPE_INV, TYPE_INV},
708         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8,  TYPE_INV, TYPE_INV, TYPE_INV},
709         {TYPE_INV, TYPE_MP,  TYPE_INV, TYPE_MP,  TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_INV},
710         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
711         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV}
712 };
713
714 static const char 
715 neg_table [] = {
716         TYPE_INV, TYPE_I4, TYPE_I8, TYPE_PTR, TYPE_R8, TYPE_INV, TYPE_INV, TYPE_INV
717 };
718
719 /* reduce the size of this table */
720 static const char
721 bin_int_table [TYPE_MAX] [TYPE_MAX] = {
722         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
723         {TYPE_INV, TYPE_I4,  TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
724         {TYPE_INV, TYPE_INV, TYPE_I8,  TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
725         {TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
726         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
727         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
728         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
729         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV}
730 };
731
732 static const char
733 bin_comp_table [TYPE_MAX] [TYPE_MAX] = {
734         {0},
735         {0, 1, 0, 1, 0, 0, 0, 0},
736         {0, 0, 1, 0, 0, 0, 0, 0},
737         {0, 1, 0, 1, 0, 2, 0, 0},
738         {0, 0, 0, 0, 1, 0, 0, 0},
739         {0, 0, 0, 2, 0, 1, 0, 0},
740         {0, 0, 0, 0, 0, 0, 3, 0},
741         {0, 0, 0, 0, 0, 0, 0, 0},
742 };
743
744 /* reduce the size of this table */
745 static const char
746 shift_table [TYPE_MAX] [TYPE_MAX] = {
747         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
748         {TYPE_INV, TYPE_I4,  TYPE_INV, TYPE_I4,  TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
749         {TYPE_INV, TYPE_I8,  TYPE_INV, TYPE_I8,  TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
750         {TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
751         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
752         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
753         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
754         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV}
755 };
756
757 static const char 
758 ldind_type [] = {
759         TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I8, TYPE_PTR, TYPE_R8, TYPE_R8, TYPE_OBJ
760 };
761
762 static const char
763 ldelem_type [] = {
764         TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I8, TYPE_PTR, TYPE_R8, TYPE_R8, TYPE_OBJ
765 };
766
767 #define ADD_INVALID(list,msg)   \
768         do {    \
769                 MonoVerifyInfo *vinfo = g_new (MonoVerifyInfo, 1);      \
770                 vinfo->status = MONO_VERIFY_ERROR;      \
771                 vinfo->message = (msg); \
772                 (list) = g_slist_prepend ((list), vinfo);       \
773                 /*G_BREAKPOINT ();*/    \
774                 goto invalid_cil;       \
775         } while (0)
776
777 #define CHECK_STACK_UNDERFLOW(num)      \
778         do {    \
779                 if (cur_stack < (num))  \
780                         ADD_INVALID (list, g_strdup_printf ("Stack underflow at 0x%04x (%d items instead of %d)", ip_offset, cur_stack, (num)));        \
781         } while (0)
782
783 #define CHECK_STACK_OVERFLOW()  \
784         do {    \
785                 if (cur_stack >= max_stack)     \
786                         ADD_INVALID (list, g_strdup_printf ("Maxstack exceeded at 0x%04x", ip_offset)); \
787         } while (0)
788
789 enum {
790         PREFIX_UNALIGNED = 1,
791         PREFIX_VOLATILE  = 2,
792         PREFIX_TAIL      = 4,
793         PREFIX_ADDR_MASK = 3,
794         PREFIX_FUNC_MASK = 4
795 };
796
797 enum {
798         CODE_SEEN = 1
799 };
800
801 typedef struct {
802         MonoType *type;
803         int stype;
804 } ILStackDesc;
805
806 typedef struct {
807         ILStackDesc *stack;
808         guint16 stack_count;
809         guint16 flags;
810 } ILCodeDesc;
811
812 static void
813 type_to_eval_stack_type (MonoType *type, ILStackDesc *stack, int take_addr) {
814         int t = type->type;
815
816         stack->type = type;
817         if (type->byref || take_addr) { /* fix double addr issue */
818                 stack->stype = TYPE_MP;
819                 return;
820         }
821
822 handle_enum:
823         switch (t) {
824         case MONO_TYPE_I1:
825         case MONO_TYPE_U1:
826         case MONO_TYPE_BOOLEAN:
827         case MONO_TYPE_I2:
828         case MONO_TYPE_U2:
829         case MONO_TYPE_CHAR:
830         case MONO_TYPE_I4:
831         case MONO_TYPE_U4:
832                 stack->stype = TYPE_I4;
833                 return;
834         case MONO_TYPE_I:
835         case MONO_TYPE_U:
836         case MONO_TYPE_PTR:
837                 stack->stype = TYPE_PTR;
838                 return;
839         case MONO_TYPE_CLASS:
840         case MONO_TYPE_STRING:
841         case MONO_TYPE_OBJECT:
842         case MONO_TYPE_SZARRAY:
843         case MONO_TYPE_ARRAY:    
844                 stack->stype = TYPE_OBJ;
845                 return;
846         case MONO_TYPE_I8:
847         case MONO_TYPE_U8:
848                 stack->stype = TYPE_I8;
849                 return;
850         case MONO_TYPE_R4:
851         case MONO_TYPE_R8:
852                 stack->stype = TYPE_R8;
853                 return;
854         case MONO_TYPE_VALUETYPE:
855                 if (type->data.klass->enumtype) {
856                         t = type->data.klass->enum_basetype->type;
857                         goto handle_enum;
858                 } else {
859                         stack->stype = TYPE_VT;
860                         return;
861                 }
862         default:
863                 g_error ("unknown type %02x in eval stack type", type->type);
864         }
865         return;
866 }
867
868 static int
869 type_from_op (int ins, ILStackDesc *arg) {
870         switch (ins) {
871         /* binops */
872         case CEE_ADD:
873         case CEE_SUB:
874         case CEE_MUL:
875         case CEE_DIV:
876         case CEE_REM:
877                 /* FIXME: check unverifiable args for TYPE_MP */
878                 return arg->stype = bin_num_table [arg->stype] [arg [1].stype];
879         case CEE_DIV_UN:
880         case CEE_REM_UN:
881         case CEE_AND:
882         case CEE_OR:
883         case CEE_XOR:
884                 return arg->stype = bin_int_table [arg->stype] [arg [1].stype];
885         case CEE_SHL:
886         case CEE_SHR:
887         case CEE_SHR_UN:
888                 return arg->stype = shift_table [arg->stype] [arg [1].stype];
889         case CEE_BEQ_S:
890         case CEE_BGE_S:
891         case CEE_BGT_S:
892         case CEE_BLE_S:
893         case CEE_BLT_S:
894         case CEE_BNE_UN_S:
895         case CEE_BGE_UN_S:
896         case CEE_BGT_UN_S:
897         case CEE_BLE_UN_S:
898         case CEE_BLT_UN_S:
899         case CEE_BEQ:
900         case CEE_BGE:
901         case CEE_BGT:
902         case CEE_BLE:
903         case CEE_BLT:
904         case CEE_BNE_UN:
905         case CEE_BGE_UN:
906         case CEE_BGT_UN:
907         case CEE_BLE_UN:
908         case CEE_BLT_UN:
909                 /* FIXME: handle some specifics with ins->next->type */
910                 return bin_comp_table [arg->stype] [arg [1].stype] ? TYPE_I4: TYPE_INV;
911         case 256+CEE_CEQ:
912         case 256+CEE_CGT:
913         case 256+CEE_CGT_UN:
914         case 256+CEE_CLT:
915         case 256+CEE_CLT_UN:
916                 return arg->stype = bin_comp_table [arg->stype] [arg [1].stype] ? TYPE_I4: TYPE_INV;
917         /* unops */
918         case CEE_NEG:
919                 return arg->stype = neg_table [arg->stype];
920         case CEE_NOT:
921                 if (arg->stype >= TYPE_I4 && arg->stype <= TYPE_PTR)
922                         return arg->stype;
923                 else
924                         return arg->stype = TYPE_INV;
925         case CEE_CONV_I1:
926         case CEE_CONV_U1:
927         case CEE_CONV_I2:
928         case CEE_CONV_U2:
929         case CEE_CONV_I4:
930         case CEE_CONV_U4:
931         case CEE_CONV_OVF_I1:
932         case CEE_CONV_OVF_U1:
933         case CEE_CONV_OVF_I2:
934         case CEE_CONV_OVF_U2:
935         case CEE_CONV_OVF_I4:
936         case CEE_CONV_OVF_U4:
937         case CEE_CONV_OVF_I1_UN:
938         case CEE_CONV_OVF_U1_UN:
939         case CEE_CONV_OVF_I2_UN:
940         case CEE_CONV_OVF_U2_UN:
941         case CEE_CONV_OVF_I4_UN:
942         case CEE_CONV_OVF_U4_UN:
943                 if (arg->stype == TYPE_INV || arg->stype >= TYPE_MP)
944                         return arg->stype = TYPE_INV;
945                 return arg->stype = TYPE_I4;
946         case CEE_CONV_I:
947         case CEE_CONV_U:
948         case CEE_CONV_OVF_I:
949         case CEE_CONV_OVF_U:
950         case CEE_CONV_OVF_I_UN:
951         case CEE_CONV_OVF_U_UN:
952                 if (arg->stype == TYPE_INV || arg->stype == TYPE_VT)
953                         return arg->stype = TYPE_INV;
954                 return arg->stype = TYPE_PTR;
955         case CEE_CONV_I8:
956         case CEE_CONV_U8:
957         case CEE_CONV_OVF_I8:
958         case CEE_CONV_OVF_U8:
959         case CEE_CONV_OVF_I8_UN:
960         case CEE_CONV_OVF_U8_UN:
961                 return arg->stype = TYPE_I8;
962         case CEE_CONV_R4:
963         case CEE_CONV_R8:
964                 return arg->stype = TYPE_R8;
965         default:
966                 g_error ("opcode 0x%04x not handled in type from op", ins);
967                 break;
968         }
969         return FALSE;
970 }
971
972 static int
973 in_any_block (MonoMethodHeader *header, guint offset)
974 {
975         int i;
976         MonoExceptionClause *clause;
977
978         for (i = 0; i < header->num_clauses; ++i) {
979                 clause = &header->clauses [i];
980                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
981                         return 1;
982                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
983                         return 1;
984                 /* need to check filter ... */
985         }
986         return 0;
987 }
988
989 static int
990 in_same_block (MonoMethodHeader *header, guint offset, guint target)
991 {
992         int i;
993         MonoExceptionClause *clause;
994
995         for (i = 0; i < header->num_clauses; ++i) {
996                 clause = &header->clauses [i];
997                 if (MONO_OFFSET_IN_CLAUSE (clause, offset) && !MONO_OFFSET_IN_CLAUSE (clause, target))
998                         return 0;
999                 if (MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
1000                         return 0;
1001                 /* need to check filter ... */
1002         }
1003         return 1;
1004 }
1005
1006 /*
1007  * A leave can't escape a finally block 
1008  */
1009 static int
1010 is_correct_leave (MonoMethodHeader *header, guint offset, guint target)
1011 {
1012         int i;
1013         MonoExceptionClause *clause;
1014
1015         for (i = 0; i < header->num_clauses; ++i) {
1016                 clause = &header->clauses [i];
1017                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY && MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
1018                         return 0;
1019                 /* need to check filter ... */
1020         }
1021         return 1;
1022 }
1023
1024 static int
1025 can_merge_stack (ILCodeDesc *a, ILCodeDesc *b)
1026 {
1027         if (!b->flags & CODE_SEEN) {
1028                 b->flags |= CODE_SEEN;
1029                 b->stack_count = a->stack_count;
1030                 /* merge types */
1031                 return 1;
1032         }
1033         if (a->stack_count != b->stack_count)
1034                 return 0;
1035         /* merge types */
1036         return 1;
1037 }
1038
1039 static int
1040 is_valid_bool_arg (ILStackDesc *arg)
1041 {
1042         switch (arg->stype) {
1043         case TYPE_I4:
1044         case TYPE_I8:
1045         case TYPE_PTR:
1046         case TYPE_MP:
1047         case TYPE_OBJ:
1048                 return TRUE;
1049         default:
1050                 return FALSE;
1051         }
1052 }
1053
1054 static int
1055 can_store_type (ILStackDesc *arg, MonoType *type)
1056 {
1057         int t = type->type;
1058         if (type->byref && arg->stype != TYPE_MP)
1059                 return FALSE;
1060 handle_enum:
1061         switch (t) {
1062         case MONO_TYPE_VOID:
1063                 return FALSE;
1064         case MONO_TYPE_I1:
1065         case MONO_TYPE_U1:
1066         case MONO_TYPE_BOOLEAN:
1067         case MONO_TYPE_I2:
1068         case MONO_TYPE_U2:
1069         case MONO_TYPE_CHAR:
1070         case MONO_TYPE_I4:
1071         case MONO_TYPE_U4:
1072                 if (arg->stype == TYPE_I4 || arg->stype == TYPE_PTR)
1073                         return TRUE;
1074                 return FALSE;
1075         case MONO_TYPE_I:
1076         case MONO_TYPE_U:
1077         case MONO_TYPE_PTR:
1078                 return TRUE;
1079         case MONO_TYPE_CLASS:
1080         case MONO_TYPE_STRING:
1081         case MONO_TYPE_OBJECT:
1082         case MONO_TYPE_SZARRAY:
1083         case MONO_TYPE_ARRAY:    
1084                 return TRUE; /* FIXME */
1085         case MONO_TYPE_I8:
1086         case MONO_TYPE_U8:
1087                 if (arg->stype == TYPE_I8)
1088                         return TRUE;
1089                 return FALSE;
1090         case MONO_TYPE_R4:
1091         case MONO_TYPE_R8:
1092                 if (arg->stype == TYPE_R8)
1093                         return TRUE;
1094                 return FALSE;
1095         case MONO_TYPE_VALUETYPE:
1096                 if (type->data.klass->enumtype) {
1097                         t = type->data.klass->enum_basetype->type;
1098                         goto handle_enum;
1099                 } else {
1100                         if (arg->type->data.klass != type->data.klass)
1101                                 return FALSE;
1102                         return TRUE;
1103                 }
1104         default:
1105                 g_error ("unknown type %02x in store type", type->type);
1106         }
1107         return FALSE;
1108 }
1109
1110 static int
1111 stind_type (int op, int type) {
1112         switch (op) {
1113         case CEE_STIND_REF:
1114                 return type == TYPE_OBJ;
1115         case CEE_STIND_I1:
1116         case CEE_STIND_I2:
1117         case CEE_STIND_I4:
1118                 return type == TYPE_I4;
1119         case CEE_STIND_I8:
1120                 return type == TYPE_I8;
1121         case CEE_STIND_R4:
1122         case CEE_STIND_R8:
1123                 return type == TYPE_R8;
1124         default:
1125                 g_assert_not_reached ();
1126         }
1127         return FALSE;
1128 }
1129
1130 /*
1131  * FIXME: need to distinguish between valid and verifiable.
1132  * Need to keep track of types on the stack.
1133  * Verify types for opcodes.
1134  */
1135 GSList*
1136 mono_method_verify (MonoMethod *method, int level)
1137 {
1138         MonoMethodHeader *header;
1139         MonoMethodSignature *signature, *csig;
1140         MonoGenericContext *generic_context = NULL;
1141         MonoMethod *cmethod;
1142         MonoClassField *field;
1143         MonoClass *klass;
1144         MonoImage *image;
1145         MonoType **params;
1146         ILStackDesc *stack;
1147         register const unsigned char *ip;
1148         register const unsigned char *end;
1149         const unsigned char *target = NULL; /* branch target */
1150         int max_args, max_stack, cur_stack, i, n, need_merge, start;
1151         guint32 token, ip_offset = 0;
1152         char *local_state = NULL;
1153         GSList *list = NULL;
1154         guint prefix = 0;
1155         ILCodeDesc *code;
1156
1157         if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1158                         (method->flags & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT))) {
1159                 return NULL;
1160         }
1161         signature = mono_method_signature (method);
1162         header = mono_method_get_header (method);
1163         ip = header->code;
1164         end = ip + header->code_size;
1165         max_args = signature->param_count + signature->hasthis;
1166         max_stack = header->max_stack;
1167         need_merge = cur_stack = 0;
1168         start = 1;
1169         image = method->klass->image;
1170         code = g_new0 (ILCodeDesc, header->code_size);
1171         stack = g_new0 (ILStackDesc, max_stack);
1172         if (signature->hasthis) {
1173                 params = g_new0 (MonoType*, max_args);
1174                 params [0] = &method->klass->this_arg;
1175                 memcpy (params + 1, signature->params, sizeof (MonoType*) * signature->param_count);
1176         } else {
1177                 params = signature->params;
1178         }
1179
1180         if (signature->is_inflated)
1181                 generic_context = ((MonoMethodInflated *) method)->context;
1182
1183         if (header->num_locals) {
1184                 local_state = g_new (char, header->num_locals);
1185                 memset (local_state, header->init_locals, header->num_locals);
1186         }
1187         /*g_print ("Method %s.%s::%s\n", method->klass->name_space, method->klass->name, method->name);*/
1188
1189         for (i = 0; i < header->num_clauses; ++i) {
1190                 MonoExceptionClause *clause = &header->clauses [i];
1191                 /* catch blocks have the exception on the stack. */
1192                 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
1193                         code [clause->handler_offset].stack_count = 1;
1194                         code [clause->handler_offset].flags |= CODE_SEEN;
1195                 }
1196         }
1197
1198         while (ip < end) {
1199                 ip_offset = ip - header->code;
1200                 if (start || !(code [ip_offset].flags & CODE_SEEN)) {
1201                         if (start) {
1202                                 /* g_print ("setting stack of IL_%04x to %d\n", ip_offset, 0); */
1203                                 cur_stack = code [ip_offset].stack_count;
1204                         } else {
1205                                 code [ip_offset].stack_count = cur_stack;
1206                         }
1207                         code [ip_offset].flags |= CODE_SEEN;
1208                 } else {
1209                         /* stack merge */
1210                         if (code [ip_offset].stack_count != cur_stack)
1211                                 ADD_INVALID (list, g_strdup_printf ("Cannot merge stack states at 0x%04x", ip_offset));
1212                 }
1213                 start = 0;
1214                 if (need_merge) {
1215                         if (!can_merge_stack (&code [ip_offset], &code [target - header->code]))
1216                                 ADD_INVALID (list, g_strdup_printf ("Cannot merge stack states at 0x%04x", ip_offset));
1217                         need_merge = 0;
1218                 }
1219 #if 0
1220                 {
1221                         char *discode;
1222                         discode = mono_disasm_code_one (NULL, method, ip, NULL);
1223                         discode [strlen (discode) - 1] = 0; /* no \n */
1224                         g_print ("%-29s (%d)\n", discode, cur_stack);
1225                         g_free (discode);
1226                 }
1227 #endif
1228
1229                 switch (*ip) {
1230                 case CEE_NOP:
1231                 case CEE_BREAK: 
1232                         ++ip;
1233                         break;
1234                 case CEE_LDARG_0:
1235                 case CEE_LDARG_1:
1236                 case CEE_LDARG_2:
1237                 case CEE_LDARG_3:
1238                         if (*ip - CEE_LDARG_0 >= max_args)
1239                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", *ip - CEE_LDARG_0, ip_offset));
1240                         CHECK_STACK_OVERFLOW ();
1241                         type_to_eval_stack_type (params [*ip - CEE_LDARG_0], stack + cur_stack, FALSE);
1242                         ++cur_stack;
1243                         ++ip;
1244                         break;
1245                 case CEE_LDLOC_0:
1246                 case CEE_LDLOC_1:
1247                 case CEE_LDLOC_2:
1248                 case CEE_LDLOC_3:
1249                         if (*ip - CEE_LDLOC_0 >= header->num_locals)
1250                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", *ip - CEE_LDLOC_0, ip_offset));
1251                         if (0 && !local_state [*ip - CEE_LDLOC_0])
1252                                 ADD_INVALID (list, g_strdup_printf ("Local var %d is initialized at 0x%04x", *ip - CEE_LDLOC_0, ip_offset));
1253                         CHECK_STACK_OVERFLOW ();
1254                         type_to_eval_stack_type (header->locals [*ip - CEE_LDLOC_0], stack + cur_stack, FALSE);
1255                         ++cur_stack;
1256                         ++ip;
1257                         break;
1258                 case CEE_STLOC_0:
1259                 case CEE_STLOC_1:
1260                 case CEE_STLOC_2:
1261                 case CEE_STLOC_3:
1262                         if (*ip - CEE_STLOC_0 >= header->num_locals)
1263                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", *ip - CEE_STLOC_0, ip_offset));
1264                         local_state [*ip - CEE_STLOC_0] = 1;
1265                         CHECK_STACK_UNDERFLOW (1);
1266                         --cur_stack;
1267                         if (!can_store_type (stack + cur_stack, header->locals [*ip - CEE_STLOC_0]))
1268                                 ADD_INVALID (list, g_strdup_printf ("Incompatible type %s in store at 0x%04x", arg_name [stack [cur_stack].stype], ip_offset));
1269                         ++ip;
1270                         break;
1271                 case CEE_LDARG_S:
1272                 case CEE_LDARGA_S:
1273                         if (ip [1] >= max_args)
1274                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", ip [1], ip_offset));
1275                         CHECK_STACK_OVERFLOW ();
1276                         type_to_eval_stack_type (params [ip [1]], stack + cur_stack, *ip == CEE_LDARGA_S);
1277                         ++cur_stack;
1278                         ip += 2;
1279                         break;
1280                 case CEE_STARG_S:
1281                         if (ip [1] >= max_args)
1282                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", ip [1], ip_offset));
1283                         CHECK_STACK_UNDERFLOW (1);
1284                         --cur_stack;
1285                         ip += 2;
1286                         break;
1287                 case CEE_LDLOC_S:
1288                 case CEE_LDLOCA_S:
1289                         if (ip [1] >= header->num_locals)
1290                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", ip [1], ip_offset));
1291                         /* no need to check if the var is initialized if the address is taken */
1292                         if (0 && *ip == CEE_LDLOC_S && !local_state [ip [1]])
1293                                 ADD_INVALID (list, g_strdup_printf ("Local var %d is initialized at 0x%04x", ip [1], ip_offset));
1294                         CHECK_STACK_OVERFLOW ();
1295                         type_to_eval_stack_type (header->locals [ip [1]], stack + cur_stack, *ip == CEE_LDLOCA_S);
1296                         ++cur_stack;
1297                         ip += 2;
1298                         break;
1299                 case CEE_STLOC_S:
1300                         if (ip [1] >= header->num_locals)
1301                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", ip [1], ip_offset));
1302                         local_state [ip [1]] = 1;
1303                         CHECK_STACK_UNDERFLOW (1);
1304                         --cur_stack;
1305                         if (!can_store_type (stack + cur_stack, header->locals [ip [1]]))
1306                                 ADD_INVALID (list, g_strdup_printf ("Incompatible type %s in store at 0x%04x", arg_name [stack [cur_stack].stype], ip_offset));
1307                         ip += 2;
1308                         break;
1309                 case CEE_LDNULL:
1310                         CHECK_STACK_OVERFLOW ();
1311                         stack [cur_stack].type = &mono_defaults.object_class->byval_arg;
1312                         stack [cur_stack].stype = TYPE_OBJ;
1313                         ++cur_stack;
1314                         ++ip;
1315                         break;
1316                 case CEE_LDC_I4_M1:
1317                 case CEE_LDC_I4_0:
1318                 case CEE_LDC_I4_1:
1319                 case CEE_LDC_I4_2:
1320                 case CEE_LDC_I4_3:
1321                 case CEE_LDC_I4_4:
1322                 case CEE_LDC_I4_5:
1323                 case CEE_LDC_I4_6:
1324                 case CEE_LDC_I4_7:
1325                 case CEE_LDC_I4_8:
1326                         CHECK_STACK_OVERFLOW ();
1327                         stack [cur_stack].type = &mono_defaults.int_class->byval_arg;
1328                         stack [cur_stack].stype = TYPE_I4;
1329                         ++cur_stack;
1330                         ++ip;
1331                         break;
1332                 case CEE_LDC_I4_S:
1333                         CHECK_STACK_OVERFLOW ();
1334                         stack [cur_stack].type = &mono_defaults.int_class->byval_arg;
1335                         stack [cur_stack].stype = TYPE_I4;
1336                         ++cur_stack;
1337                         ip += 2;
1338                         break;
1339                 case CEE_LDC_I4:
1340                         CHECK_STACK_OVERFLOW ();
1341                         stack [cur_stack].type = &mono_defaults.int_class->byval_arg;
1342                         stack [cur_stack].stype = TYPE_I4;
1343                         ++cur_stack;
1344                         ip += 5;
1345                         break;
1346                 case CEE_LDC_I8:
1347                         CHECK_STACK_OVERFLOW ();
1348                         stack [cur_stack].type = &mono_defaults.int64_class->byval_arg;
1349                         stack [cur_stack].stype = TYPE_I8;
1350                         ++cur_stack;
1351                         ip += 9;
1352                         break;
1353                 case CEE_LDC_R4:
1354                         CHECK_STACK_OVERFLOW ();
1355                         stack [cur_stack].type = &mono_defaults.double_class->byval_arg;
1356                         stack [cur_stack].stype = TYPE_R8;
1357                         ++cur_stack;
1358                         ip += 5;
1359                         break;
1360                 case CEE_LDC_R8:
1361                         CHECK_STACK_OVERFLOW ();
1362                         stack [cur_stack].type = &mono_defaults.double_class->byval_arg;
1363                         stack [cur_stack].stype = TYPE_R8;
1364                         ++cur_stack;
1365                         ip += 9;
1366                         break;
1367                 case CEE_UNUSED99: ++ip; break; /* warn/error instead? */
1368                 case CEE_DUP:
1369                         CHECK_STACK_UNDERFLOW (1);
1370                         CHECK_STACK_OVERFLOW ();
1371                         stack [cur_stack] = stack [cur_stack - 1];
1372                         ++cur_stack;
1373                         ++ip;
1374                         break;
1375                 case CEE_POP:
1376                         CHECK_STACK_UNDERFLOW (1);
1377                         --cur_stack;
1378                         ++ip;
1379                         break;
1380                 case CEE_JMP:
1381                         if (cur_stack)
1382                                 ADD_INVALID (list, g_strdup_printf ("Eval stack must be empty in jmp at 0x%04x", ip_offset));
1383                         token = read32 (ip + 1);
1384                         if (in_any_block (header, ip_offset))
1385                                 ADD_INVALID (list, g_strdup_printf ("jmp cannot escape exception blocks at 0x%04x", ip_offset));
1386                         /*
1387                          * FIXME: check signature, retval, arguments etc.
1388                          */
1389                         ip += 5;
1390                         break;
1391                 case CEE_CALL:
1392                 case CEE_CALLVIRT:
1393                         token = read32 (ip + 1);
1394                         /*
1395                          * FIXME: we could just load the signature ...
1396                          */
1397                         cmethod = mono_get_method_full (image, token, NULL, generic_context);
1398                         if (!cmethod)
1399                                 ADD_INVALID (list, g_strdup_printf ("Method 0x%08x not found at 0x%04x", token, ip_offset));
1400                         if (mono_method_signature (cmethod)) {
1401                                 csig = mono_method_signature (cmethod);
1402                         } else {
1403                                 csig = mono_method_get_signature (cmethod, image, token);
1404                         }
1405
1406                         CHECK_STACK_UNDERFLOW (csig->param_count + csig->hasthis);
1407                         cur_stack -= csig->param_count + csig->hasthis;
1408                         if (csig->ret->type != MONO_TYPE_VOID) {
1409                                 CHECK_STACK_OVERFLOW ();
1410                                 type_to_eval_stack_type (csig->ret, stack + cur_stack, FALSE);
1411                                 ++cur_stack;
1412                         }
1413                         ip += 5;
1414                         break;
1415                 case CEE_CALLI:
1416                         token = read32 (ip + 1);
1417                         /*
1418                          * FIXME: check signature, retval, arguments etc.
1419                          */
1420                         ip += 5;
1421                         break;
1422                 case CEE_RET:
1423                         if (signature->ret->type != MONO_TYPE_VOID) {
1424                                 CHECK_STACK_UNDERFLOW (1);
1425                                 --cur_stack;
1426                                 if (!can_store_type (stack + cur_stack, signature->ret))
1427                                         ADD_INVALID (list, g_strdup_printf ("Incompatible type %s in ret at 0x%04x", arg_name [stack [cur_stack].stype], ip_offset));
1428                         }
1429                         if (cur_stack)
1430                                 ADD_INVALID (list, g_strdup_printf ("Stack not empty (%d) after ret at 0x%04x", cur_stack, ip_offset));
1431                         cur_stack = 0;
1432                         if (in_any_block (header, ip_offset))
1433                                 ADD_INVALID (list, g_strdup_printf ("ret cannot escape exception blocks at 0x%04x", ip_offset));
1434                         ++ip;
1435                         start = 1;
1436                         break;
1437                 case CEE_BR_S:
1438                         target = ip + (signed char)ip [1] + 2;
1439                         if (target >= end || target < header->code)
1440                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1441                         if (!in_same_block (header, ip_offset, target - header->code))
1442                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1443                         ip += 2;
1444                         start = 1;
1445                         break;
1446                 case CEE_BRFALSE_S:
1447                 case CEE_BRTRUE_S:
1448                         target = ip + (signed char)ip [1] + 2;
1449                         if (target >= end || target < header->code)
1450                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1451                         if (!in_same_block (header, ip_offset, target - header->code))
1452                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1453                         CHECK_STACK_UNDERFLOW (1);
1454                         --cur_stack;
1455                         if (!is_valid_bool_arg (stack + cur_stack))
1456                                 ADD_INVALID (list, g_strdup_printf ("Argument type %s not valid for brtrue/brfalse at 0x%04x", arg_name [stack [cur_stack].stype], ip_offset));
1457                         ip += 2;
1458                         need_merge = 1;
1459                         break;
1460                 case CEE_BEQ_S:
1461                 case CEE_BGE_S:
1462                 case CEE_BGT_S:
1463                 case CEE_BLE_S:
1464                 case CEE_BLT_S:
1465                 case CEE_BNE_UN_S:
1466                 case CEE_BGE_UN_S:
1467                 case CEE_BGT_UN_S:
1468                 case CEE_BLE_UN_S:
1469                 case CEE_BLT_UN_S:
1470                         target = ip + (signed char)ip [1] + 2;
1471                         if (target >= end || target < header->code)
1472                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1473                         if (!in_same_block (header, ip_offset, target - header->code))
1474                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1475                         CHECK_STACK_UNDERFLOW (2);
1476                         cur_stack -= 2;
1477                         if (type_from_op (*ip, stack + cur_stack) == TYPE_INV)
1478                                 ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
1479                         ip += 2;
1480                         need_merge = 1;
1481                         break;
1482                 case CEE_BR:
1483                         target = ip + (gint32)read32 (ip + 1) + 5;
1484                         if (target >= end || target < header->code)
1485                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1486                         if (!in_same_block (header, ip_offset, target - header->code))
1487                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1488                         ip += 5;
1489                         start = 1;
1490                         break;
1491                 case CEE_BRFALSE:
1492                 case CEE_BRTRUE:
1493                         target = ip + (gint32)read32 (ip + 1) + 5;
1494                         if (target >= end || target < header->code)
1495                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1496                         if (!in_same_block (header, ip_offset, target - header->code))
1497                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1498                         CHECK_STACK_UNDERFLOW (1);
1499                         --cur_stack;
1500                         if (!is_valid_bool_arg (stack + cur_stack))
1501                                 ADD_INVALID (list, g_strdup_printf ("Argument type %s not valid for brtrue/brfalse at 0x%04x", arg_name [stack [cur_stack].stype], ip_offset));
1502                         ip += 5;
1503                         need_merge = 1;
1504                         break;
1505                 case CEE_BEQ:
1506                 case CEE_BGE:
1507                 case CEE_BGT:
1508                 case CEE_BLE:
1509                 case CEE_BLT:
1510                 case CEE_BNE_UN:
1511                 case CEE_BGE_UN:
1512                 case CEE_BGT_UN:
1513                 case CEE_BLE_UN:
1514                 case CEE_BLT_UN:
1515                         target = ip + (gint32)read32 (ip + 1) + 5;
1516                         if (target >= end || target < header->code)
1517                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1518                         if (!in_same_block (header, ip_offset, target - header->code))
1519                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1520                         CHECK_STACK_UNDERFLOW (2);
1521                         cur_stack -= 2;
1522                         if (type_from_op (*ip, stack + cur_stack) == TYPE_INV)
1523                                 ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
1524                         ip += 5;
1525                         need_merge = 1;
1526                         break;
1527                 case CEE_SWITCH:
1528                         n = read32 (ip + 1);
1529                         target = ip + sizeof (guint32) * n;
1530                         /* FIXME: check that ip is in range (and within the same exception block) */
1531                         for (i = 0; i < n; ++i)
1532                                 if (target + (gint32) read32 (ip + 5 + i * sizeof (gint32)) >= end || target + (gint32) read32 (ip + 5 + i * sizeof (gint32)) < header->code)
1533                                         ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1534                         CHECK_STACK_UNDERFLOW (1);
1535                         --cur_stack;
1536                         if (stack [cur_stack].stype != TYPE_I4)
1537                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument to switch at 0x%04x", ip_offset));
1538                         ip += 5 + sizeof (guint32) * n;
1539                         break;
1540                 case CEE_LDIND_I1:
1541                 case CEE_LDIND_U1:
1542                 case CEE_LDIND_I2:
1543                 case CEE_LDIND_U2:
1544                 case CEE_LDIND_I4:
1545                 case CEE_LDIND_U4:
1546                 case CEE_LDIND_I8:
1547                 case CEE_LDIND_I:
1548                 case CEE_LDIND_R4:
1549                 case CEE_LDIND_R8:
1550                 case CEE_LDIND_REF:
1551                         CHECK_STACK_UNDERFLOW (1);
1552                         if (stack [cur_stack - 1].stype != TYPE_PTR && stack [cur_stack - 1].stype != TYPE_MP)
1553                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument to ldind at 0x%04x", ip_offset));
1554                         stack [cur_stack - 1].stype = ldind_type [*ip - CEE_LDIND_I1];
1555                         ++ip;
1556                         break;
1557                 case CEE_STIND_REF:
1558                 case CEE_STIND_I1:
1559                 case CEE_STIND_I2:
1560                 case CEE_STIND_I4:
1561                 case CEE_STIND_I8:
1562                 case CEE_STIND_R4:
1563                 case CEE_STIND_R8:
1564                         CHECK_STACK_UNDERFLOW (2);
1565                         cur_stack -= 2;
1566                         if (stack [cur_stack].stype != TYPE_PTR && stack [cur_stack].stype != TYPE_MP)
1567                                 ADD_INVALID (list, g_strdup_printf ("Invalid pointer argument to stind at 0x%04x", ip_offset));
1568                         if (!stind_type (*ip, stack [cur_stack + 1].stype))
1569                                 ADD_INVALID (list, g_strdup_printf ("Incompatible value argument to stind at 0x%04x", ip_offset));
1570                         ++ip;
1571                         break;
1572                 case CEE_ADD:
1573                 case CEE_SUB:
1574                 case CEE_MUL:
1575                 case CEE_DIV:
1576                 case CEE_DIV_UN:
1577                 case CEE_REM:
1578                 case CEE_REM_UN:
1579                 case CEE_AND:
1580                 case CEE_OR:
1581                 case CEE_XOR:
1582                 case CEE_SHL:
1583                 case CEE_SHR:
1584                 case CEE_SHR_UN:
1585                         CHECK_STACK_UNDERFLOW (2);
1586                         --cur_stack;
1587                         if (type_from_op (*ip, stack + cur_stack - 1) == TYPE_INV)
1588                                 ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
1589                         ++ip;
1590                         break;
1591                 case CEE_NEG:
1592                 case CEE_NOT:
1593                 case CEE_CONV_I1:
1594                 case CEE_CONV_I2:
1595                 case CEE_CONV_I4:
1596                 case CEE_CONV_I8:
1597                 case CEE_CONV_R4:
1598                 case CEE_CONV_R8:
1599                 case CEE_CONV_U4:
1600                 case CEE_CONV_U8:
1601                         CHECK_STACK_UNDERFLOW (1);
1602                         if (type_from_op (*ip, stack + cur_stack - 1) == TYPE_INV)
1603                                 ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
1604                         ++ip;
1605                         break;
1606                 case CEE_CPOBJ:
1607                         token = read32 (ip + 1);
1608                         CHECK_STACK_UNDERFLOW (2);
1609                         cur_stack -= 2;
1610                         ip += 5;
1611                         break;
1612                 case CEE_LDOBJ:
1613                         token = read32 (ip + 1);
1614                         CHECK_STACK_UNDERFLOW (1);
1615                         if (stack [cur_stack - 1].stype != TYPE_MP)
1616                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument to ldobj at 0x%04x", ip_offset));
1617                         klass = mono_class_get_full (image, token, generic_context);
1618                         if (!klass)
1619                                 ADD_INVALID (list, g_strdup_printf ("Cannot load class from token 0x%08x at 0x%04x", token, ip_offset));
1620                         if (!klass->valuetype)
1621                                 ADD_INVALID (list, g_strdup_printf ("Class is not a valuetype at 0x%04x", ip_offset));
1622                         stack [cur_stack - 1].stype = TYPE_VT;
1623                         stack [cur_stack - 1].type = &klass->byval_arg;
1624                         ip += 5;
1625                         break;
1626                 case CEE_LDSTR:
1627                         token = read32 (ip + 1);
1628                         CHECK_STACK_OVERFLOW ();
1629                         stack [cur_stack].type = &mono_defaults.string_class->byval_arg;
1630                         stack [cur_stack].stype = TYPE_OBJ;
1631                         ++cur_stack;
1632                         ip += 5;
1633                         break;
1634                 case CEE_NEWOBJ:
1635                         token = read32 (ip + 1);
1636                         /*
1637                          * FIXME: we could just load the signature ...
1638                          */
1639                         cmethod = mono_get_method_full (image, token, NULL, generic_context);
1640                         if (!cmethod)
1641                                 ADD_INVALID (list, g_strdup_printf ("Constructor 0x%08x not found at 0x%04x", token, ip_offset));
1642                         csig = mono_method_signature (cmethod);
1643                         CHECK_STACK_UNDERFLOW (csig->param_count);
1644                         cur_stack -= csig->param_count;
1645                         CHECK_STACK_OVERFLOW ();
1646                         stack [cur_stack].type = &cmethod->klass->byval_arg;
1647                         stack [cur_stack].stype = cmethod->klass->valuetype? TYPE_VT: TYPE_OBJ;
1648                         ++cur_stack;
1649                         ip += 5;
1650                         break;
1651                 case CEE_CASTCLASS:
1652                 case CEE_ISINST:
1653                         token = read32 (ip + 1);
1654                         CHECK_STACK_UNDERFLOW (1);
1655                         ip += 5;
1656                         break;
1657                 case CEE_CONV_R_UN:
1658                         CHECK_STACK_UNDERFLOW (1);
1659                         ++ip;
1660                         break;
1661                 case CEE_UNUSED58:
1662                 case CEE_UNUSED1:
1663                         ++ip; /* warn, error ? */
1664                         break;
1665                 case CEE_UNBOX:
1666                         token = read32 (ip + 1);
1667                         CHECK_STACK_UNDERFLOW (1);
1668                         if (stack [cur_stack - 1].stype != TYPE_OBJ)
1669                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument %s to unbox at 0x%04x", arg_name [stack [cur_stack - 1].stype], ip_offset));
1670                         stack [cur_stack - 1].stype = TYPE_MP;
1671                         stack [cur_stack - 1].type = NULL;
1672                         ip += 5;
1673                         break;
1674                 case CEE_THROW:
1675                         CHECK_STACK_UNDERFLOW (1);
1676                         --cur_stack;
1677                         ++ip;
1678                         start = 1;
1679                         break;
1680                 case CEE_LDFLD:
1681                         CHECK_STACK_UNDERFLOW (1);
1682                         if (stack [cur_stack - 1].stype != TYPE_OBJ && stack [cur_stack - 1].stype != TYPE_MP)
1683                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument %s to ldfld at 0x%04x", arg_name [stack [cur_stack].stype], ip_offset));
1684                         token = read32 (ip + 1);
1685                         field = mono_field_from_token (image, token, &klass, generic_context);
1686                         if (!field)
1687                                 ADD_INVALID (list, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
1688                         type_to_eval_stack_type (field->type, stack + cur_stack - 1, FALSE);
1689                         ip += 5;
1690                         break;
1691                 case CEE_LDFLDA:
1692                         CHECK_STACK_UNDERFLOW (1);
1693                         if (stack [cur_stack - 1].stype != TYPE_OBJ && stack [cur_stack - 1].stype != TYPE_MP)
1694                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument to ldflda at 0x%04x", ip_offset));
1695                         token = read32 (ip + 1);
1696                         field = mono_field_from_token (image, token, &klass, generic_context);
1697                         if (!field)
1698                                 ADD_INVALID (list, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
1699                         type_to_eval_stack_type (field->type, stack + cur_stack - 1, TRUE);
1700                         ip += 5;
1701                         break;
1702                 case CEE_STFLD:
1703                         CHECK_STACK_UNDERFLOW (2);
1704                         cur_stack -= 2;
1705                         if (stack [cur_stack].stype != TYPE_OBJ && stack [cur_stack].stype != TYPE_MP)
1706                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument to stfld at 0x%04x", ip_offset));
1707                         token = read32 (ip + 1);
1708                         field = mono_field_from_token (image, token, &klass, generic_context);
1709                         if (!field)
1710                                 ADD_INVALID (list, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
1711                         /* can_store */
1712                         ip += 5;
1713                         break;
1714                 case CEE_LDSFLD:
1715                         CHECK_STACK_OVERFLOW ();
1716                         token = read32 (ip + 1);
1717                         field = mono_field_from_token (image, token, &klass, generic_context);
1718                         if (!field)
1719                                 ADD_INVALID (list, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
1720                         type_to_eval_stack_type (field->type, stack + cur_stack, FALSE);
1721                         ++cur_stack;
1722                         ip += 5;
1723                         break;
1724                 case CEE_LDSFLDA:
1725                         CHECK_STACK_OVERFLOW ();
1726                         token = read32 (ip + 1);
1727                         field = mono_field_from_token (image, token, &klass, generic_context);
1728                         if (!field)
1729                                 ADD_INVALID (list, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
1730                         type_to_eval_stack_type (field->type, stack + cur_stack, TRUE);
1731                         ++cur_stack;
1732                         ip += 5;
1733                         break;
1734                 case CEE_STSFLD:
1735                         CHECK_STACK_UNDERFLOW (1);
1736                         --cur_stack;
1737                         token = read32 (ip + 1);
1738                         field = mono_field_from_token (image, token, &klass, generic_context);
1739                         if (!field)
1740                                 ADD_INVALID (list, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
1741                         /* can store */
1742                         ip += 5;
1743                         break;
1744                 case CEE_STOBJ:
1745                         CHECK_STACK_UNDERFLOW (2);
1746                         cur_stack -= 2;
1747                         token = read32 (ip + 1);
1748                         ip += 5;
1749                         break;
1750                 case CEE_CONV_OVF_I1_UN:
1751                 case CEE_CONV_OVF_I2_UN:
1752                 case CEE_CONV_OVF_I4_UN:
1753                 case CEE_CONV_OVF_I8_UN:
1754                 case CEE_CONV_OVF_U1_UN:
1755                 case CEE_CONV_OVF_U2_UN:
1756                 case CEE_CONV_OVF_U4_UN:
1757                 case CEE_CONV_OVF_U8_UN:
1758                 case CEE_CONV_OVF_I_UN:
1759                 case CEE_CONV_OVF_U_UN:
1760                         CHECK_STACK_UNDERFLOW (1);
1761                         if (type_from_op (*ip, stack + cur_stack - 1) == TYPE_INV)
1762                                 ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
1763                         ++ip;
1764                         break;
1765                 case CEE_BOX:
1766                         CHECK_STACK_UNDERFLOW (1);
1767                         token = read32 (ip + 1);
1768                         if (stack [cur_stack - 1].stype == TYPE_OBJ)
1769                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument %s to box at 0x%04x", arg_name [stack [cur_stack - 1].stype], ip_offset));
1770                         stack [cur_stack - 1].stype = TYPE_OBJ;
1771                         ip += 5;
1772                         break;
1773                 case CEE_NEWARR:
1774                         CHECK_STACK_UNDERFLOW (1);
1775                         token = read32 (ip + 1);
1776                         stack [cur_stack - 1].stype = TYPE_OBJ;
1777                         ip += 5;
1778                         break;
1779                 case CEE_LDLEN:
1780                         CHECK_STACK_UNDERFLOW (1);
1781                         if (stack [cur_stack - 1].stype != TYPE_OBJ)
1782                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument to ldlen at 0x%04x", ip_offset));
1783                         stack [cur_stack - 1].type = &mono_defaults.int_class->byval_arg; /* FIXME: use a native int type */
1784                         stack [cur_stack - 1].stype = TYPE_PTR;
1785                         ++ip;
1786                         break;
1787                 case CEE_LDELEMA:
1788                         CHECK_STACK_UNDERFLOW (2);
1789                         --cur_stack;
1790                         if (stack [cur_stack - 1].stype != TYPE_OBJ)
1791                                 ADD_INVALID (list, g_strdup_printf ("Invalid array argument to ldelema at 0x%04x", ip_offset));
1792                         if (stack [cur_stack].stype != TYPE_I4 && stack [cur_stack].stype != TYPE_PTR)
1793                                 ADD_INVALID (list, g_strdup_printf ("Array index needs to be Int32 or IntPtr at 0x%04x", ip_offset));
1794                         stack [cur_stack - 1].stype = TYPE_MP;
1795                         token = read32 (ip + 1);
1796                         ip += 5;
1797                         break;
1798                 case CEE_LDELEM_I1:
1799                 case CEE_LDELEM_U1:
1800                 case CEE_LDELEM_I2:
1801                 case CEE_LDELEM_U2:
1802                 case CEE_LDELEM_I4:
1803                 case CEE_LDELEM_U4:
1804                 case CEE_LDELEM_I8:
1805                 case CEE_LDELEM_I:
1806                 case CEE_LDELEM_R4:
1807                 case CEE_LDELEM_R8:
1808                 case CEE_LDELEM_REF:
1809                         CHECK_STACK_UNDERFLOW (2);
1810                         --cur_stack;
1811                         if (stack [cur_stack - 1].stype != TYPE_OBJ)
1812                                 ADD_INVALID (list, g_strdup_printf ("Invalid array argument to ldelem at 0x%04x", ip_offset));
1813                         if (stack [cur_stack].stype != TYPE_I4 && stack [cur_stack].stype != TYPE_PTR)
1814                                 ADD_INVALID (list, g_strdup_printf ("Array index needs to be Int32 or IntPtr at 0x%04x", ip_offset));
1815                         stack [cur_stack - 1].stype = ldelem_type [*ip - CEE_LDELEM_I1];
1816                         ++ip;
1817                         break;
1818                 case CEE_STELEM_I:
1819                 case CEE_STELEM_I1:
1820                 case CEE_STELEM_I2:
1821                 case CEE_STELEM_I4:
1822                 case CEE_STELEM_I8:
1823                 case CEE_STELEM_R4:
1824                 case CEE_STELEM_R8:
1825                 case CEE_STELEM_REF:
1826                         CHECK_STACK_UNDERFLOW (3);
1827                         cur_stack -= 3;
1828                         ++ip;
1829                         break;
1830                 case CEE_LDELEM_ANY:
1831                 case CEE_STELEM_ANY:
1832                 case CEE_UNBOX_ANY:
1833                 case CEE_UNUSED5:
1834                 case CEE_UNUSED6:
1835                 case CEE_UNUSED7:
1836                 case CEE_UNUSED8:
1837                 case CEE_UNUSED9:
1838                 case CEE_UNUSED10:
1839                 case CEE_UNUSED11:
1840                 case CEE_UNUSED12:
1841                 case CEE_UNUSED13:
1842                 case CEE_UNUSED14:
1843                 case CEE_UNUSED15:
1844                 case CEE_UNUSED16:
1845                 case CEE_UNUSED17:
1846                         ++ip; /* warn, error ? */
1847                         break;
1848                 case CEE_CONV_OVF_I1:
1849                 case CEE_CONV_OVF_U1:
1850                 case CEE_CONV_OVF_I2:
1851                 case CEE_CONV_OVF_U2:
1852                 case CEE_CONV_OVF_I4:
1853                 case CEE_CONV_OVF_U4:
1854                 case CEE_CONV_OVF_I8:
1855                 case CEE_CONV_OVF_U8:
1856                         CHECK_STACK_UNDERFLOW (1);
1857                         if (type_from_op (*ip, stack + cur_stack - 1) == TYPE_INV)
1858                                 ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
1859                         ++ip;
1860                         break;
1861                 case CEE_UNUSED50:
1862                 case CEE_UNUSED18:
1863                 case CEE_UNUSED19:
1864                 case CEE_UNUSED20:
1865                 case CEE_UNUSED21:
1866                 case CEE_UNUSED22:
1867                 case CEE_UNUSED23:
1868                         ++ip; /* warn, error ? */
1869                         break;
1870                 case CEE_REFANYVAL:
1871                         CHECK_STACK_UNDERFLOW (1);
1872                         ++ip;
1873                         break;
1874                 case CEE_CKFINITE:
1875                         CHECK_STACK_UNDERFLOW (1);
1876                         ++ip;
1877                         break;
1878                 case CEE_UNUSED24:
1879                 case CEE_UNUSED25:
1880                         ++ip; /* warn, error ? */
1881                         break;
1882                 case CEE_MKREFANY:
1883                         CHECK_STACK_UNDERFLOW (1);
1884                         token = read32 (ip + 1);
1885                         ip += 5;
1886                         break;
1887                 case CEE_UNUSED59:
1888                 case CEE_UNUSED60:
1889                 case CEE_UNUSED61:
1890                 case CEE_UNUSED62:
1891                 case CEE_UNUSED63:
1892                 case CEE_UNUSED64:
1893                 case CEE_UNUSED65:
1894                 case CEE_UNUSED66:
1895                 case CEE_UNUSED67:
1896                         ++ip; /* warn, error ? */
1897                         break;
1898                 case CEE_LDTOKEN:
1899                         CHECK_STACK_OVERFLOW ();
1900                         token = read32 (ip + 1);
1901                         ++cur_stack;
1902                         ip += 5;
1903                         break;
1904                 case CEE_CONV_U2:
1905                 case CEE_CONV_U1:
1906                 case CEE_CONV_I:
1907                 case CEE_CONV_OVF_I:
1908                 case CEE_CONV_OVF_U:
1909                         CHECK_STACK_UNDERFLOW (1);
1910                         if (type_from_op (*ip, stack + cur_stack - 1) == TYPE_INV)
1911                                 ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
1912                         ++ip;
1913                         break;
1914                 case CEE_ADD_OVF:
1915                 case CEE_ADD_OVF_UN:
1916                 case CEE_MUL_OVF:
1917                 case CEE_MUL_OVF_UN:
1918                 case CEE_SUB_OVF:
1919                 case CEE_SUB_OVF_UN:
1920                         CHECK_STACK_UNDERFLOW (2);
1921                         --cur_stack;
1922                         ++ip;
1923                         break;
1924                 case CEE_ENDFINALLY:
1925                         ++ip;
1926                         start = 1;
1927                         break;
1928                 case CEE_LEAVE:
1929                         target = ip + (gint32)read32(ip + 1) + 5;
1930                         if (target >= end || target < header->code)
1931                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1932                         if (!is_correct_leave (header, ip_offset, target - header->code))
1933                                 ADD_INVALID (list, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ip_offset));
1934                         ip += 5;
1935                         start = 1;
1936                         break;
1937                 case CEE_LEAVE_S:
1938                         target = ip + (signed char)ip [1] + 2;
1939                         if (target >= end || target < header->code)
1940                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1941                         if (!is_correct_leave (header, ip_offset, target - header->code))
1942                                 ADD_INVALID (list, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ip_offset));
1943                         ip += 2;
1944                         start = 1;
1945                         break;
1946                 case CEE_STIND_I:
1947                         CHECK_STACK_UNDERFLOW (2);
1948                         cur_stack -= 2;
1949                         ++ip;
1950                         break;
1951                 case CEE_CONV_U:
1952                         CHECK_STACK_UNDERFLOW (1);
1953                         ++ip;
1954                         break;
1955                 case CEE_UNUSED26:
1956                 case CEE_UNUSED27:
1957                 case CEE_UNUSED28:
1958                 case CEE_UNUSED29:
1959                 case CEE_UNUSED30:
1960                 case CEE_UNUSED31:
1961                 case CEE_UNUSED32:
1962                 case CEE_UNUSED33:
1963                 case CEE_UNUSED34:
1964                 case CEE_UNUSED35:
1965                 case CEE_UNUSED36:
1966                 case CEE_UNUSED37:
1967                 case CEE_UNUSED38:
1968                 case CEE_UNUSED39:
1969                 case CEE_UNUSED40:
1970                 case CEE_UNUSED41:
1971                 case CEE_UNUSED42:
1972                 case CEE_UNUSED43:
1973                 case CEE_UNUSED44:
1974                 case CEE_UNUSED45:
1975                 case CEE_UNUSED46:
1976                 case CEE_UNUSED47:
1977                 case CEE_UNUSED48:
1978                         ++ip;
1979                         break;
1980                 case CEE_PREFIX7:
1981                 case CEE_PREFIX6:
1982                 case CEE_PREFIX5:
1983                 case CEE_PREFIX4:
1984                 case CEE_PREFIX3:
1985                 case CEE_PREFIX2:
1986                 case CEE_PREFIXREF:
1987                         ++ip;
1988                         break;
1989                 case CEE_PREFIX1:
1990                         ++ip;
1991                         switch (*ip) {
1992                         case CEE_ARGLIST:
1993                                 CHECK_STACK_OVERFLOW ();
1994                                 ++ip;
1995                                 break;
1996                         case CEE_CEQ:
1997                         case CEE_CGT:
1998                         case CEE_CGT_UN:
1999                         case CEE_CLT:
2000                         case CEE_CLT_UN:
2001                                 CHECK_STACK_UNDERFLOW (2);
2002                                 --cur_stack;
2003                                 if (type_from_op (256 + *ip, stack + cur_stack - 1) == TYPE_INV)
2004                                         ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0xFE 0x%02x at 0x%04x", *ip, ip_offset));
2005                                 ++ip;
2006                                 break;
2007                         case CEE_LDFTN:
2008                                 CHECK_STACK_OVERFLOW ();
2009                                 token = read32 (ip + 1);
2010                                 ip += 5;
2011                                 stack [cur_stack].stype = TYPE_PTR;
2012                                 cur_stack++;
2013                                 break;
2014                         case CEE_LDVIRTFTN:
2015                                 CHECK_STACK_UNDERFLOW (1);
2016                                 token = read32 (ip + 1);
2017                                 ip += 5;
2018                                 if (stack [cur_stack - 1].stype != TYPE_OBJ)
2019                                         ADD_INVALID (list, g_strdup_printf ("Invalid argument to ldvirtftn at 0x%04x", ip_offset));
2020                                 stack [cur_stack - 1].stype = TYPE_PTR;
2021                                 break;
2022                         case CEE_UNUSED56:
2023                                 ++ip;
2024                                 break;
2025                         case CEE_LDARG:
2026                         case CEE_LDARGA:
2027                                 if (read16 (ip + 1) >= max_args)
2028                                         ADD_INVALID (list, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", read16 (ip + 1), ip_offset));
2029                                 CHECK_STACK_OVERFLOW ();
2030                                 ++cur_stack;
2031                                 ip += 3;
2032                                 break;
2033                         case CEE_STARG:
2034                                 if (read16 (ip + 1) >= max_args)
2035                                         ADD_INVALID (list, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", read16(ip + 1), ip_offset));
2036                                 CHECK_STACK_UNDERFLOW (1);
2037                                 --cur_stack;
2038                                 ip += 3;
2039                                 break;
2040                         case CEE_LDLOC:
2041                         case CEE_LDLOCA:
2042                                 n = read16 (ip + 1);
2043                                 if (n >= header->num_locals)
2044                                         ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", n, ip_offset));
2045                                 /* no need to check if the var is initialized if the address is taken */
2046                                 if (0 && *ip == CEE_LDLOC && !local_state [n])
2047                                         ADD_INVALID (list, g_strdup_printf ("Local var %d is initialized at 0x%04x", n, ip_offset));
2048                                 CHECK_STACK_OVERFLOW ();
2049                                 type_to_eval_stack_type (header->locals [n], stack + cur_stack, *ip == CEE_LDLOCA);
2050                                 ++cur_stack;
2051                                 ip += 3;
2052                                 break;
2053                         case CEE_STLOC:
2054                                 n = read16 (ip + 1);
2055                                 if (n >= header->num_locals)
2056                                         ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", n, ip_offset));
2057                                 local_state [n] = 1;
2058                                 CHECK_STACK_UNDERFLOW (1);
2059                                 --cur_stack;
2060                                 if (!can_store_type (stack + cur_stack, header->locals [n]))
2061                                         ADD_INVALID (list, g_strdup_printf ("Incompatible type %s in store at 0x%04x", arg_name [stack [cur_stack].stype], ip_offset));
2062                                 ip += 3;
2063                                 break;
2064                         case CEE_LOCALLOC:
2065                                 if (cur_stack != 1)
2066                                         ADD_INVALID (list, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ip_offset));
2067                                 if (stack [cur_stack -1].stype != TYPE_I4 && stack [cur_stack -1].stype != TYPE_PTR)
2068                                         ADD_INVALID (list, g_strdup_printf ("Invalid argument to localloc at 0x%04x", ip_offset));
2069                                 stack [cur_stack -1].stype = TYPE_MP;
2070                                 ++ip;
2071                                 break;
2072                         case CEE_UNUSED57:
2073                                 ++ip;
2074                                 break;
2075                         case CEE_ENDFILTER:
2076                                 if (cur_stack != 1)
2077                                         ADD_INVALID (list, g_strdup_printf ("Stack must have only filter result in endfilter at 0x%04x", ip_offset));
2078                                 ++ip;
2079                                 break;
2080                         case CEE_UNALIGNED_:
2081                                 prefix |= PREFIX_UNALIGNED;
2082                                 ++ip;
2083                                 break;
2084                         case CEE_VOLATILE_:
2085                                 prefix |= PREFIX_VOLATILE;
2086                                 ++ip;
2087                                 break;
2088                         case CEE_TAIL_:
2089                                 prefix |= PREFIX_TAIL;
2090                                 ++ip;
2091                                 if (ip < end && (*ip != CEE_CALL && *ip != CEE_CALLI && *ip != CEE_CALLVIRT))
2092                                         ADD_INVALID (list, g_strdup_printf ("tail prefix must be used only with call opcodes at 0x%04x", ip_offset));
2093                                 break;
2094                         case CEE_INITOBJ:
2095                                 CHECK_STACK_UNDERFLOW (1);
2096                                 token = read32 (ip + 1);
2097                                 ip += 5;
2098                                 --cur_stack;
2099                                 break;
2100                         case CEE_CONSTRAINED_:
2101                                 token = read32 (ip + 1);
2102                                 ip += 5;
2103                                 break;
2104                         case CEE_CPBLK:
2105                                 CHECK_STACK_UNDERFLOW (3);
2106                                 ip++;
2107                                 break;
2108                         case CEE_INITBLK:
2109                                 CHECK_STACK_UNDERFLOW (3);
2110                                 ip++;
2111                                 break;
2112                         case CEE_NO_:
2113                                 ip += 2;
2114                                 break;
2115                         case CEE_RETHROW:
2116                                 ++ip;
2117                                 break;
2118                         case CEE_UNUSED:
2119                                 ++ip;
2120                                 break;
2121                         case CEE_SIZEOF:
2122                                 CHECK_STACK_OVERFLOW ();
2123                                 token = read32 (ip + 1);
2124                                 ip += 5;
2125                                 stack [cur_stack].type = &mono_defaults.uint_class->byval_arg;
2126                                 stack [cur_stack].stype = TYPE_I4;
2127                                 cur_stack++;
2128                                 break;
2129                         case CEE_REFANYTYPE:
2130                                 CHECK_STACK_UNDERFLOW (1);
2131                                 ++ip;
2132                                 break;
2133                         case CEE_UNUSED53:
2134                         case CEE_UNUSED54:
2135                         case CEE_UNUSED55:
2136                         case CEE_UNUSED70:
2137                                 ++ip;
2138                                 break;
2139                         }
2140                 }
2141         }
2142         /*
2143          * if ip != end we overflowed: mark as error.
2144          */
2145         if (ip != end || !start) {
2146                 ADD_INVALID (list, g_strdup_printf ("Run ahead of method code at 0x%04x", ip_offset));
2147         }
2148 invalid_cil:
2149
2150         g_free (local_state);
2151         g_free (code);
2152         g_free (stack);
2153         if (signature->hasthis)
2154                 g_free (params);
2155         return list;
2156 }
2157
2158 typedef struct {
2159         const char *name;
2160         guint64 offset;
2161 } FieldDesc;
2162
2163 typedef struct {
2164         const char *name;
2165         const FieldDesc *fields;
2166 } ClassDesc;
2167
2168 static const FieldDesc 
2169 typebuilder_fields[] = {
2170         {"tname", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, name)},
2171         {"nspace", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, nspace)},
2172         {"parent", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, parent)},
2173         {"interfaces", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, interfaces)},
2174         {"methods", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, methods)},
2175         {"properties", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, properties)},
2176         {"fields", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, fields)},
2177         {"attrs", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, attrs)},
2178         {"table_idx", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, table_idx)},
2179         {NULL, 0}
2180 };
2181
2182 static const FieldDesc 
2183 modulebuilder_fields[] = {
2184         {"types", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, types)},
2185         {"cattrs", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, cattrs)},
2186         {"guid", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, guid)},
2187         {"table_idx", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, table_idx)},
2188         {NULL, 0}
2189 };
2190
2191 static const FieldDesc 
2192 assemblybuilder_fields[] = {
2193         {"entry_point", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, entry_point)},
2194         {"modules", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, modules)},
2195         {"name", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, name)},
2196         {"resources", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, resources)},
2197         {"version", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, version)},
2198         {"culture", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, culture)},
2199         {NULL, 0}
2200 };
2201
2202 static const FieldDesc 
2203 ctorbuilder_fields[] = {
2204         {"ilgen", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, ilgen)},
2205         {"parameters", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, parameters)},
2206         {"attrs", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, attrs)},
2207         {"iattrs", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, iattrs)},
2208         {"table_idx", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, table_idx)},
2209         {"call_conv", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, call_conv)},
2210         {"type", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, type)},
2211         {NULL, 0}
2212 };
2213
2214 static const FieldDesc 
2215 methodbuilder_fields[] = {
2216         {"mhandle", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, mhandle)},
2217         {"rtype", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, rtype)},
2218         {"parameters", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, parameters)},
2219         {"attrs", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, attrs)},
2220         {"iattrs", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, iattrs)},
2221         {"name", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, name)},
2222         {"table_idx", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, table_idx)},
2223         {"code", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, code)},
2224         {"ilgen", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, ilgen)},
2225         {"type", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, type)},
2226         {"pinfo", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, pinfo)},
2227         {"pi_dll", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, dll)},
2228         {"pi_entry", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, dllentry)},
2229         {"charset", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, charset)},
2230         {"extra_flags", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, extra_flags)},
2231         {"native_cc", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, native_cc)},
2232         {"call_conv", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, call_conv)},
2233         {NULL, 0}
2234 };
2235
2236 static const FieldDesc 
2237 fieldbuilder_fields[] = {
2238         {"attrs", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, attrs)},
2239         {"type", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, type)},
2240         {"name", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, name)},
2241         {"def_value", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, def_value)},
2242         {"offset", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, offset)},
2243         {"table_idx", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, table_idx)},
2244         {NULL, 0}
2245 };
2246
2247 static const FieldDesc 
2248 propertybuilder_fields[] = {
2249         {"attrs", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, attrs)},
2250         {"name", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, name)},
2251         {"type", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, type)},
2252         {"parameters", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, parameters)},
2253         {"def_value", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, def_value)},
2254         {"set_method", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, set_method)},
2255         {"get_method", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, get_method)},
2256         {"table_idx", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, table_idx)},
2257         {NULL, 0}
2258 };
2259
2260 static const FieldDesc 
2261 ilgenerator_fields[] = {
2262         {"code", G_STRUCT_OFFSET (MonoReflectionILGen, code)},
2263         {"code_len", G_STRUCT_OFFSET (MonoReflectionILGen, code_len)},
2264         {"max_stack", G_STRUCT_OFFSET (MonoReflectionILGen, max_stack)},
2265         {"cur_stack", G_STRUCT_OFFSET (MonoReflectionILGen, cur_stack)},
2266         {"locals", G_STRUCT_OFFSET (MonoReflectionILGen, locals)},
2267         {"ex_handlers", G_STRUCT_OFFSET (MonoReflectionILGen, ex_handlers)},
2268         {NULL, 0}
2269 };
2270
2271 static const FieldDesc 
2272 ilexinfo_fields[] = {
2273         {"handlers", G_STRUCT_OFFSET (MonoILExceptionInfo, handlers)},
2274         {"start", G_STRUCT_OFFSET (MonoILExceptionInfo, start)},
2275         {"len", G_STRUCT_OFFSET (MonoILExceptionInfo, len)},
2276         {"end", G_STRUCT_OFFSET (MonoILExceptionInfo, label)},
2277         {NULL, 0}
2278 };
2279
2280 static const FieldDesc 
2281 ilexblock_fields[] = {
2282         {"extype", G_STRUCT_OFFSET (MonoILExceptionBlock, extype)},
2283         {"type", G_STRUCT_OFFSET (MonoILExceptionBlock, type)},
2284         {"start", G_STRUCT_OFFSET (MonoILExceptionBlock, start)},
2285         {"len", G_STRUCT_OFFSET (MonoILExceptionBlock, len)},
2286         {"filter_offset", G_STRUCT_OFFSET (MonoILExceptionBlock, filter_offset)},
2287         {NULL, 0}
2288 };
2289
2290 static const ClassDesc
2291 emit_classes_to_check [] = {
2292         {"TypeBuilder", typebuilder_fields},
2293         {"ModuleBuilder", modulebuilder_fields},
2294         {"AssemblyBuilder", assemblybuilder_fields},
2295         {"ConstructorBuilder", ctorbuilder_fields},
2296         {"MethodBuilder", methodbuilder_fields},
2297         {"FieldBuilder", fieldbuilder_fields},
2298         {"PropertyBuilder", propertybuilder_fields},
2299         {"ILGenerator", ilgenerator_fields},
2300         {"ILExceptionBlock", ilexblock_fields},
2301         {"ILExceptionInfo", ilexinfo_fields},
2302         {NULL, NULL}
2303 };
2304
2305 static const FieldDesc 
2306 monoevent_fields[] = {
2307         {"klass", G_STRUCT_OFFSET (MonoReflectionEvent, klass)},
2308         {"handle", G_STRUCT_OFFSET (MonoReflectionEvent, event)},
2309         {NULL, 0}
2310 };
2311
2312 static const FieldDesc 
2313 monoproperty_fields[] = {
2314         {"klass", G_STRUCT_OFFSET (MonoReflectionProperty, klass)},
2315         {"prop", G_STRUCT_OFFSET (MonoReflectionProperty, property)},
2316         {NULL, 0}
2317 };
2318
2319 static const FieldDesc 
2320 monofield_fields[] = {
2321         {"klass", G_STRUCT_OFFSET (MonoReflectionField, klass)},
2322         {"fhandle", G_STRUCT_OFFSET (MonoReflectionField, field)},
2323         {NULL, 0}
2324 };
2325
2326 static const FieldDesc 
2327 monomethodinfo_fields[] = {
2328         {"parent", G_STRUCT_OFFSET (MonoMethodInfo, parent)},
2329         {"ret", G_STRUCT_OFFSET (MonoMethodInfo, ret)},
2330         {"attrs", G_STRUCT_OFFSET (MonoMethodInfo, attrs)},
2331         {"iattrs", G_STRUCT_OFFSET (MonoMethodInfo, implattrs)},
2332         {NULL, 0}
2333 };
2334
2335 static const FieldDesc 
2336 monopropertyinfo_fields[] = {
2337         {"parent", G_STRUCT_OFFSET (MonoPropertyInfo, parent)},
2338         {"name", G_STRUCT_OFFSET (MonoPropertyInfo, name)},
2339         {"get_method", G_STRUCT_OFFSET (MonoPropertyInfo, get)},
2340         {"set_method", G_STRUCT_OFFSET (MonoPropertyInfo, set)},
2341         {"attrs", G_STRUCT_OFFSET (MonoPropertyInfo, attrs)},
2342         {NULL, 0}
2343 };
2344
2345 static const FieldDesc 
2346 monomethod_fields[] = {
2347         {"mhandle", G_STRUCT_OFFSET (MonoReflectionMethod, method)},
2348         {NULL, 0}
2349 };
2350
2351 static const FieldDesc 
2352 monocmethod_fields[] = {
2353         {"mhandle", G_STRUCT_OFFSET (MonoReflectionMethod, method)},
2354         {NULL, 0}
2355 };
2356
2357 static const FieldDesc 
2358 pinfo_fields[] = {
2359         {"ClassImpl", G_STRUCT_OFFSET (MonoReflectionParameter, ClassImpl)},
2360         {"DefaultValueImpl", G_STRUCT_OFFSET (MonoReflectionParameter, DefaultValueImpl)},
2361         {"MemberImpl", G_STRUCT_OFFSET (MonoReflectionParameter, MemberImpl)},
2362         {"NameImpl", G_STRUCT_OFFSET (MonoReflectionParameter, NameImpl)},
2363         {"PositionImpl", G_STRUCT_OFFSET (MonoReflectionParameter, PositionImpl)},
2364         {"AttrsImpl", G_STRUCT_OFFSET (MonoReflectionParameter, AttrsImpl)},
2365         {NULL, 0}
2366 };
2367
2368 static const ClassDesc
2369 reflection_classes_to_check [] = {
2370         {"MonoEvent", monoevent_fields},
2371         {"MonoProperty", monoproperty_fields},
2372         {"MonoField", monofield_fields},
2373         {"MonoMethodInfo", monomethodinfo_fields},
2374         {"MonoPropertyInfo", monopropertyinfo_fields},
2375         {"MonoMethod", monomethod_fields},
2376         {"MonoCMethod", monocmethod_fields},
2377         {"ParameterInfo", pinfo_fields},
2378         {NULL, NULL}
2379 };
2380
2381 static FieldDesc 
2382 enuminfo_fields[] = {
2383         {"utype", G_STRUCT_OFFSET (MonoEnumInfo, utype)},
2384         {"values", G_STRUCT_OFFSET (MonoEnumInfo, values)},
2385         {"names", G_STRUCT_OFFSET (MonoEnumInfo, names)},
2386         {NULL, 0}
2387 };
2388
2389 static FieldDesc 
2390 delegate_fields[] = {
2391         {"target_type", G_STRUCT_OFFSET (MonoDelegate, target_type)},
2392         {"m_target", G_STRUCT_OFFSET (MonoDelegate, target)},
2393         {"method_name", G_STRUCT_OFFSET (MonoDelegate, method_name)},
2394         {"method_ptr", G_STRUCT_OFFSET (MonoDelegate, method_ptr)},
2395         {"delegate_trampoline", G_STRUCT_OFFSET (MonoDelegate, delegate_trampoline)},
2396         {"method_info", G_STRUCT_OFFSET (MonoDelegate, method_info)},
2397         {NULL, 0}
2398 };
2399
2400 static FieldDesc 
2401 multicast_delegate_fields[] = {
2402         {"prev", G_STRUCT_OFFSET (MonoMulticastDelegate, prev)},
2403         {NULL, 0}
2404 };
2405
2406 static FieldDesc 
2407 async_result_fields[] = {
2408         {"async_state", G_STRUCT_OFFSET (MonoAsyncResult, async_state)},
2409         {"handle", G_STRUCT_OFFSET (MonoAsyncResult, handle)},
2410         {"async_delegate", G_STRUCT_OFFSET (MonoAsyncResult, async_delegate)},
2411         {"data", G_STRUCT_OFFSET (MonoAsyncResult, data)},
2412         {"sync_completed", G_STRUCT_OFFSET (MonoAsyncResult, sync_completed)},
2413         {"completed", G_STRUCT_OFFSET (MonoAsyncResult, completed)},
2414         {"endinvoke_called", G_STRUCT_OFFSET (MonoAsyncResult, endinvoke_called)},
2415         {"async_callback", G_STRUCT_OFFSET (MonoAsyncResult, async_callback)},
2416         {NULL, 0}
2417 };
2418
2419 static FieldDesc 
2420 exception_fields[] = {
2421         {"trace_ips", G_STRUCT_OFFSET (MonoException, trace_ips)},
2422         {"inner_exception", G_STRUCT_OFFSET (MonoException, inner_ex)},
2423         {"message", G_STRUCT_OFFSET (MonoException, message)},
2424         {"help_link", G_STRUCT_OFFSET (MonoException, help_link)},
2425         {"class_name", G_STRUCT_OFFSET (MonoException, class_name)},
2426         {"stack_trace", G_STRUCT_OFFSET (MonoException, stack_trace)},
2427         {"remote_stack_trace", G_STRUCT_OFFSET (MonoException, remote_stack_trace)},
2428         {"remote_stack_index", G_STRUCT_OFFSET (MonoException, remote_stack_index)},
2429         {"hresult", G_STRUCT_OFFSET (MonoException, hresult)},
2430         {"source", G_STRUCT_OFFSET (MonoException, source)},
2431         {NULL, 0}
2432 };
2433
2434 static const ClassDesc
2435 system_classes_to_check [] = {
2436         {"Exception", exception_fields},
2437         {"MonoEnumInfo", enuminfo_fields},
2438         {"Delegate", delegate_fields},
2439         {"MulticastDelegate", multicast_delegate_fields},
2440         {NULL, NULL}
2441 };
2442
2443 static FieldDesc 
2444 stack_frame_fields [] = {
2445         {"ilOffset", G_STRUCT_OFFSET (MonoStackFrame, il_offset)},
2446         {"nativeOffset", G_STRUCT_OFFSET (MonoStackFrame, native_offset)},
2447         {"methodBase", G_STRUCT_OFFSET (MonoStackFrame, method)},
2448         {"fileName", G_STRUCT_OFFSET (MonoStackFrame, filename)},
2449         {"lineNumber", G_STRUCT_OFFSET (MonoStackFrame, line)},
2450         {"columnNumber", G_STRUCT_OFFSET (MonoStackFrame, column)},
2451         {NULL, 0}
2452 };
2453
2454 static const ClassDesc
2455 system_diagnostics_classes_to_check [] = {
2456         {"StackFrame", stack_frame_fields},
2457         {NULL, NULL}
2458 };
2459
2460 static FieldDesc 
2461 mono_method_message_fields[] = {
2462         {"method", G_STRUCT_OFFSET (MonoMethodMessage, method)},
2463         {"args", G_STRUCT_OFFSET (MonoMethodMessage, args)},
2464         {"names", G_STRUCT_OFFSET (MonoMethodMessage, names)},
2465         {"arg_types", G_STRUCT_OFFSET (MonoMethodMessage, arg_types)},
2466         {"ctx", G_STRUCT_OFFSET (MonoMethodMessage, ctx)},
2467         {"rval", G_STRUCT_OFFSET (MonoMethodMessage, rval)},
2468         {"exc", G_STRUCT_OFFSET (MonoMethodMessage, exc)},
2469         {NULL, 0}
2470 };
2471
2472 static const ClassDesc
2473 messaging_classes_to_check [] = {
2474         {"AsyncResult", async_result_fields},
2475         {"MonoMethodMessage", mono_method_message_fields},
2476         {NULL, NULL}
2477 };
2478
2479 static FieldDesc 
2480 transparent_proxy_fields[] = {
2481         {"_rp", G_STRUCT_OFFSET (MonoTransparentProxy, rp)},
2482         {"_class", G_STRUCT_OFFSET (MonoTransparentProxy, remote_class)},
2483         {NULL, 0}
2484 };
2485
2486 static FieldDesc 
2487 real_proxy_fields[] = {
2488         {"class_to_proxy", G_STRUCT_OFFSET (MonoRealProxy, class_to_proxy)},
2489         {NULL, 0}
2490 };
2491
2492 static const ClassDesc
2493 proxy_classes_to_check [] = {
2494         {"TransparentProxy", transparent_proxy_fields},
2495         {"RealProxy", real_proxy_fields},
2496         {NULL, NULL}
2497 };
2498
2499 static FieldDesc 
2500 wait_handle_fields[] = {
2501         {"os_handle", G_STRUCT_OFFSET (MonoWaitHandle, handle)},
2502         {"disposed", G_STRUCT_OFFSET (MonoWaitHandle, disposed)},
2503         {NULL, 0}
2504 };
2505
2506 static FieldDesc 
2507 thread_fields[] = {
2508         {"system_thread_handle", G_STRUCT_OFFSET (MonoThread, handle)},
2509         {"threadpool_thread", G_STRUCT_OFFSET (MonoThread, threadpool_thread)},
2510         {"state", G_STRUCT_OFFSET (MonoThread, state)},
2511         {"abort_exc", G_STRUCT_OFFSET (MonoThread, abort_exc)},
2512         {"abort_state", G_STRUCT_OFFSET (MonoThread, abort_state)},
2513         {"thread_id", G_STRUCT_OFFSET (MonoThread, tid)},
2514         {NULL, 0}
2515 };
2516
2517 static const ClassDesc
2518 threading_classes_to_check [] = {
2519         {"Thread", thread_fields},
2520         {"WaitHandle", wait_handle_fields},
2521         {NULL, NULL}
2522 };
2523
2524 static const FieldDesc
2525 cinfo_fields[] = {
2526         {"datetime_format", G_STRUCT_OFFSET (MonoCultureInfo, datetime_format)},
2527         {"number_format", G_STRUCT_OFFSET (MonoCultureInfo, number_format)},
2528         {"textinfo", G_STRUCT_OFFSET (MonoCultureInfo, textinfo)},
2529         {"name", G_STRUCT_OFFSET (MonoCultureInfo, name)},
2530         {"displayname", G_STRUCT_OFFSET (MonoCultureInfo, displayname)},
2531         {"englishname", G_STRUCT_OFFSET (MonoCultureInfo, englishname)},
2532         {"nativename", G_STRUCT_OFFSET (MonoCultureInfo, nativename)},
2533         {"iso3lang", G_STRUCT_OFFSET (MonoCultureInfo, iso3lang)},
2534         {"iso2lang", G_STRUCT_OFFSET (MonoCultureInfo, iso2lang)},
2535         {"icu_name", G_STRUCT_OFFSET (MonoCultureInfo, icu_name)},
2536         {"win3lang", G_STRUCT_OFFSET (MonoCultureInfo, win3lang)},
2537         {"compareinfo", G_STRUCT_OFFSET (MonoCultureInfo, compareinfo)},
2538         {NULL, 0}
2539 };
2540
2541 static const FieldDesc
2542 dtfinfo_fields[] = {
2543         {"amDesignator", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, AMDesignator)},
2544         {"pmDesignator", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, PMDesignator)},
2545         {"dayNames", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, DayNames)},
2546         {"monthNames", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, MonthNames)},
2547         {NULL, 0}
2548 };
2549
2550 static const FieldDesc
2551 nfinfo_fields[] = {
2552         {"decimalFormats", G_STRUCT_OFFSET (MonoNumberFormatInfo, decimalFormats)},
2553         {"currencySymbol", G_STRUCT_OFFSET (MonoNumberFormatInfo, currencySymbol)},
2554         {"percentSymbol", G_STRUCT_OFFSET (MonoNumberFormatInfo, percentSymbol)},
2555         {"positiveSign", G_STRUCT_OFFSET (MonoNumberFormatInfo, positiveSign)},
2556         {NULL, 0}
2557 };
2558
2559 static const FieldDesc
2560 compinfo_fields[] = {
2561         {"lcid", G_STRUCT_OFFSET (MonoCompareInfo, lcid)},
2562         {"ICU_collator", G_STRUCT_OFFSET (MonoCompareInfo, ICU_collator)},
2563         {NULL, 0}
2564 };
2565
2566 static const FieldDesc
2567 sortkey_fields[] = {
2568         {"str", G_STRUCT_OFFSET (MonoSortKey, str)},
2569         {"options", G_STRUCT_OFFSET (MonoSortKey, options)},
2570         {"key", G_STRUCT_OFFSET (MonoSortKey, key)},
2571         {"lcid", G_STRUCT_OFFSET (MonoSortKey, lcid)},
2572         {NULL, 0}
2573 };
2574
2575 static const ClassDesc
2576 globalization_classes_to_check [] = {
2577         {"CultureInfo", cinfo_fields},
2578         {"DateTimeFormatInfo", dtfinfo_fields},
2579         {"NumberFormatInfo", nfinfo_fields},
2580         {"CompareInfo", compinfo_fields},
2581         {"SortKey", sortkey_fields},
2582         {NULL, NULL}
2583 };
2584
2585 typedef struct {
2586         const char *name;
2587         const ClassDesc *types;
2588 } NameSpaceDesc;
2589
2590 static const NameSpaceDesc
2591 namespaces_to_check[] = {
2592         {"System.Runtime.Remoting.Proxies", proxy_classes_to_check},
2593         {"System.Runtime.Remoting.Messaging", messaging_classes_to_check},
2594         {"System.Reflection.Emit", emit_classes_to_check},
2595         {"System.Reflection", reflection_classes_to_check},
2596         {"System.Threading", threading_classes_to_check},
2597         {"System.Diagnostics", system_diagnostics_classes_to_check},
2598         {"System", system_classes_to_check},
2599         {"System.Globalization", globalization_classes_to_check},
2600         {NULL, NULL}
2601 };
2602
2603 static char*
2604 check_corlib (MonoImage *corlib)
2605 {
2606         MonoClass *klass;
2607         MonoClassField *field;
2608         const FieldDesc *fdesc;
2609         const ClassDesc *cdesc;
2610         const NameSpaceDesc *ndesc;
2611         gint struct_offset;
2612         GString *result = NULL;
2613
2614         for (ndesc = namespaces_to_check; ndesc->name; ++ndesc) {
2615                 for (cdesc = ndesc->types; cdesc->name; ++cdesc) {
2616                         klass = mono_class_from_name (corlib, ndesc->name, cdesc->name);
2617                         if (!klass) {
2618                                 if (!result)
2619                                         result = g_string_new ("");
2620                                 g_string_append_printf (result, "Cannot find class %s\n", cdesc->name);
2621                                 continue;
2622                         }
2623                         mono_class_init (klass);
2624                         /*
2625                          * FIXME: we should also check the size of valuetypes, or
2626                          * we're going to have trouble when we access them in arrays.
2627                          */
2628                         if (klass->valuetype)
2629                                 struct_offset = sizeof (MonoObject);
2630                         else
2631                                 struct_offset = 0;
2632                         for (fdesc = cdesc->fields; fdesc->name; ++fdesc) {
2633                                 field = mono_class_get_field_from_name (klass, fdesc->name);
2634                                 if (!field || (field->offset != (fdesc->offset + struct_offset))) {
2635                                         if (!result)
2636                                                 result = g_string_new ("");
2637                                         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));
2638                                 }
2639                         }
2640                 }
2641         }
2642         if (result)
2643                 return g_string_free (result, FALSE);
2644         return NULL;
2645 }
2646
2647 char*
2648 mono_verify_corlib () {
2649         return check_corlib (mono_defaults.corlib);
2650 }
2651
2652