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