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