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