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