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