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