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