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>
19 * Pull the list of opcodes
21 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
25 #include "mono/cil/opcode.def"
30 #ifdef MONO_VERIFIER_DEBUG
31 #define VERIFIER_DEBUG(code) do { code } while (0)
33 #define VERIFIER_DEBUG(code)
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)
40 #define ADD_VERIFY_INFO(__ctx, __msg, __status) \
42 MonoVerifyInfo *vinfo = g_new (MonoVerifyInfo, 1); \
43 vinfo->status = __status; \
44 vinfo->message = ( __msg ); \
45 (__ctx)->list = g_slist_prepend ((__ctx)->list, vinfo); \
48 #define ADD_VERIFY_ERROR(__ctx, __msg) \
50 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR); \
54 #define CODE_NOT_VERIFIABLE(__ctx, __msg) \
56 if ((__ctx)->verifiable) { \
57 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE); \
58 (__ctx)->verifiable = 0; \
59 if (IS_FAIL_FAST_MODE (__ctx)) \
64 #define UNMASK_TYPE(type) ((type) & TYPE_MASK)
65 #define IS_MANAGED_POINTER(type) (((type) & POINTER_MASK) == POINTER_MASK)
66 #define IS_NULL_LITERAL(type) (((type) & NULL_LITERAL_MASK) == NULL_LITERAL_MASK)
68 /*Flags to be used with ILCodeDesc::flags */
70 /*Instruction has not been processed.*/
71 IL_CODE_FLAG_NOT_PROCESSED = 0,
72 /*Instruction was decoded by mono_method_verify loop.*/
73 IL_CODE_FLAG_SEEN = 1,
74 /*Instruction was target of a branch or is at a protected block boundary.*/
75 IL_CODE_FLAG_WAS_TARGET = 2,
76 /*Used by stack_init to avoid double initialize each entry.*/
77 IL_CODE_FLAG_STACK_INITED = 4,
78 /*Used by merge_stacks to decide if it should just copy the eval stack.*/
79 IL_CODE_STACK_MERGED = 8,
111 /*TODO get rid of target here, need_merge in mono_method_verify and hoist the merging code in the branching code*/
115 MonoMethodSignature *signature;
116 MonoMethodHeader *header;
118 MonoGenericContext *generic_context;
124 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, int start, gboolean external);
126 //////////////////////////////////////////////////////////////////
131 TYPE_INV = 0, /* leave at 0. */
136 /* Used by operator tables to resolve pointer types (managed & unmanaged) and by unmanaged pointer types*/
138 /* value types and classes */
140 /* Number of types, used to define the size of the tables*/
141 TYPE_MAX = 8, /* FIXME: This should probably be 7, but would require all the tables to be updated */
143 /* Used by tables to signal that a result is not verifiable*/
144 NON_VERIFIABLE_RESULT = 0x80,
146 /*Mask used to extract just the type, excluding flags */
149 /* The stack type is a managed pointer, unmask the value to res */
150 POINTER_MASK = 0x100,
152 /* Controlled Mutability Manager Pointer */
155 /* The stack type is a null literal*/
156 NULL_LITERAL_MASK = 0x400,
159 static const char* const
160 type_names [TYPE_MAX] = {
166 "TYPE_PTR", /* FIXME: Give an appropriate name */
171 PREFIX_UNALIGNED = 1,
174 PREFIX_ADDR_MASK = 3,
180 //////////////////////////////////////////////////////////////////
182 mono_free_verify_list (GSList *list)
184 MonoVerifyInfo *info;
187 for (tmp = list; tmp; tmp = tmp->next) {
189 g_free (info->message);
195 #define ADD_ERROR(list,msg) \
197 MonoVerifyInfo *vinfo = g_new (MonoVerifyInfo, 1); \
198 vinfo->status = MONO_VERIFY_ERROR; \
199 vinfo->message = (msg); \
200 (list) = g_slist_prepend ((list), vinfo); \
203 #define ADD_WARN(list,code,msg) \
205 MonoVerifyInfo *vinfo = g_new (MonoVerifyInfo, 1); \
206 vinfo->status = (code); \
207 vinfo->message = (msg); \
208 (list) = g_slist_prepend ((list), vinfo); \
212 valid_cultures[][9] = {
213 "ar-SA", "ar-IQ", "ar-EG", "ar-LY",
214 "ar-DZ", "ar-MA", "ar-TN", "ar-OM",
215 "ar-YE", "ar-SY", "ar-JO", "ar-LB",
216 "ar-KW", "ar-AE", "ar-BH", "ar-QA",
217 "bg-BG", "ca-ES", "zh-TW", "zh-CN",
218 "zh-HK", "zh-SG", "zh-MO", "cs-CZ",
219 "da-DK", "de-DE", "de-CH", "de-AT",
220 "de-LU", "de-LI", "el-GR", "en-US",
221 "en-GB", "en-AU", "en-CA", "en-NZ",
222 "en-IE", "en-ZA", "en-JM", "en-CB",
223 "en-BZ", "en-TT", "en-ZW", "en-PH",
224 "es-ES-Ts", "es-MX", "es-ES-Is", "es-GT",
225 "es-CR", "es-PA", "es-DO", "es-VE",
226 "es-CO", "es-PE", "es-AR", "es-EC",
227 "es-CL", "es-UY", "es-PY", "es-BO",
228 "es-SV", "es-HN", "es-NI", "es-PR",
229 "Fi-FI", "fr-FR", "fr-BE", "fr-CA",
230 "Fr-CH", "fr-LU", "fr-MC", "he-IL",
231 "hu-HU", "is-IS", "it-IT", "it-CH",
232 "Ja-JP", "ko-KR", "nl-NL", "nl-BE",
233 "nb-NO", "nn-NO", "pl-PL", "pt-BR",
234 "pt-PT", "ro-RO", "ru-RU", "hr-HR",
235 "Lt-sr-SP", "Cy-sr-SP", "sk-SK", "sq-AL",
236 "sv-SE", "sv-FI", "th-TH", "tr-TR",
237 "ur-PK", "id-ID", "uk-UA", "be-BY",
238 "sl-SI", "et-EE", "lv-LV", "lt-LT",
239 "fa-IR", "vi-VN", "hy-AM", "Lt-az-AZ",
241 "eu-ES", "mk-MK", "af-ZA",
242 "ka-GE", "fo-FO", "hi-IN", "ms-MY",
243 "ms-BN", "kk-KZ", "ky-KZ", "sw-KE",
244 "Lt-uz-UZ", "Cy-uz-UZ", "tt-TA", "pa-IN",
245 "gu-IN", "ta-IN", "te-IN", "kn-IN",
246 "mr-IN", "sa-IN", "mn-MN", "gl-ES",
247 "kok-IN", "syr-SY", "div-MV"
251 is_valid_culture (const char *cname)
257 for (i = 0; i < G_N_ELEMENTS (valid_cultures); ++i) {
258 if (g_strcasecmp (valid_cultures [i], cname)) {
267 is_valid_assembly_flags (guint32 flags) {
268 /* Metadata: 22.1.2 */
269 flags &= ~(0x8000 | 0x4000); /* ignore reserved bits 0x0030? */
270 return ((flags == 1) || (flags == 0));
274 is_valid_blob (MonoImage *image, guint32 blob_index, int notnull)
277 const char *p, *blob_end;
279 if (blob_index >= image->heap_blob.size)
281 p = mono_metadata_blob_heap (image, blob_index);
282 size = mono_metadata_decode_blob_size (p, &blob_end);
283 if (blob_index + size + (blob_end-p) > image->heap_blob.size)
285 if (notnull && !size)
291 is_valid_string (MonoImage *image, guint32 str_index, int notnull)
293 const char *p, *blob_end, *res;
295 if (str_index >= image->heap_strings.size)
297 res = p = mono_metadata_string_heap (image, str_index);
298 blob_end = mono_metadata_string_heap (image, image->heap_strings.size - 1);
302 * FIXME: should check it's a valid utf8 string, too.
304 while (p <= blob_end) {
309 return *p? NULL: res;
313 is_valid_cls_ident (const char *p)
316 * FIXME: we need the full unicode glib support for this.
317 * Check: http://www.unicode.org/unicode/reports/tr15/Identifier.java
318 * We do the lame thing for now.
324 if (!isalnum (*p) && *p != '_')
332 is_valid_filename (const char *p)
336 return strpbrk (p, "\\//:")? 0: 1;
340 verify_assembly_table (MonoImage *image, GSList *list, int level)
342 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
343 guint32 cols [MONO_ASSEMBLY_SIZE];
346 if (level & MONO_VERIFY_ERROR) {
348 ADD_ERROR (list, g_strdup ("Assembly table may only have 0 or 1 rows"));
349 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
351 switch (cols [MONO_ASSEMBLY_HASH_ALG]) {
352 case ASSEMBLY_HASH_NONE:
353 case ASSEMBLY_HASH_MD5:
354 case ASSEMBLY_HASH_SHA1:
357 ADD_ERROR (list, g_strdup_printf ("Hash algorithm 0x%x unknown", cols [MONO_ASSEMBLY_HASH_ALG]));
360 if (!is_valid_assembly_flags (cols [MONO_ASSEMBLY_FLAGS]))
361 ADD_ERROR (list, g_strdup_printf ("Invalid flags in assembly: 0x%x", cols [MONO_ASSEMBLY_FLAGS]));
363 if (!is_valid_blob (image, cols [MONO_ASSEMBLY_PUBLIC_KEY], FALSE))
364 ADD_ERROR (list, g_strdup ("Assembly public key is an invalid index"));
366 if (!(p = is_valid_string (image, cols [MONO_ASSEMBLY_NAME], TRUE))) {
367 ADD_ERROR (list, g_strdup ("Assembly name is invalid"));
369 if (strpbrk (p, ":\\/."))
370 ADD_ERROR (list, g_strdup_printf ("Assembly name `%s' contains invalid chars", p));
373 if (!(p = is_valid_string (image, cols [MONO_ASSEMBLY_CULTURE], FALSE))) {
374 ADD_ERROR (list, g_strdup ("Assembly culture is an invalid index"));
376 if (!is_valid_culture (p))
377 ADD_ERROR (list, g_strdup_printf ("Assembly culture `%s' is invalid", p));
384 verify_assemblyref_table (MonoImage *image, GSList *list, int level)
386 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
387 guint32 cols [MONO_ASSEMBLYREF_SIZE];
391 if (level & MONO_VERIFY_ERROR) {
392 for (i = 0; i < t->rows; ++i) {
393 mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
394 if (!is_valid_assembly_flags (cols [MONO_ASSEMBLYREF_FLAGS]))
395 ADD_ERROR (list, g_strdup_printf ("Invalid flags in assemblyref row %d: 0x%x", i + 1, cols [MONO_ASSEMBLY_FLAGS]));
397 if (!is_valid_blob (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], FALSE))
398 ADD_ERROR (list, g_strdup_printf ("AssemblyRef public key in row %d is an invalid index", i + 1));
400 if (!(p = is_valid_string (image, cols [MONO_ASSEMBLYREF_CULTURE], FALSE))) {
401 ADD_ERROR (list, g_strdup_printf ("AssemblyRef culture in row %d is invalid", i + 1));
403 if (!is_valid_culture (p))
404 ADD_ERROR (list, g_strdup_printf ("AssemblyRef culture `%s' in row %d is invalid", p, i + 1));
407 if (cols [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob (image, cols [MONO_ASSEMBLYREF_HASH_VALUE], TRUE))
408 ADD_ERROR (list, g_strdup_printf ("AssemblyRef hash value in row %d is invalid or not null and empty", i + 1));
411 if (level & MONO_VERIFY_WARNING) {
412 /* check for duplicated rows */
413 for (i = 0; i < t->rows; ++i) {
420 verify_class_layout_table (MonoImage *image, GSList *list, int level)
422 MonoTableInfo *t = &image->tables [MONO_TABLE_CLASSLAYOUT];
423 MonoTableInfo *tdef = &image->tables [MONO_TABLE_TYPEDEF];
424 guint32 cols [MONO_CLASS_LAYOUT_SIZE];
427 if (level & MONO_VERIFY_ERROR) {
428 for (i = 0; i < t->rows; ++i) {
429 mono_metadata_decode_row (t, i, cols, MONO_CLASS_LAYOUT_SIZE);
431 if (cols [MONO_CLASS_LAYOUT_PARENT] > tdef->rows || !cols [MONO_CLASS_LAYOUT_PARENT]) {
432 ADD_ERROR (list, g_strdup_printf ("Parent in class layout is invalid in row %d", i + 1));
434 value = mono_metadata_decode_row_col (tdef, cols [MONO_CLASS_LAYOUT_PARENT] - 1, MONO_TYPEDEF_FLAGS);
435 if (value & TYPE_ATTRIBUTE_INTERFACE)
436 ADD_ERROR (list, g_strdup_printf ("Parent in class layout row %d is an interface", i + 1));
437 if (value & TYPE_ATTRIBUTE_AUTO_LAYOUT)
438 ADD_ERROR (list, g_strdup_printf ("Parent in class layout row %d is AutoLayout", i + 1));
439 if (value & TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT) {
440 switch (cols [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
441 case 0: case 1: case 2: case 4: case 8: case 16:
442 case 32: case 64: case 128: break;
444 ADD_ERROR (list, g_strdup_printf ("Packing size %d in class layout row %d is invalid", cols [MONO_CLASS_LAYOUT_PACKING_SIZE], i + 1));
446 } else if (value & TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
448 * FIXME: LAMESPEC: it claims it must be 0 (it's 1, instead).
449 if (cols [MONO_CLASS_LAYOUT_PACKING_SIZE])
450 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));
454 * FIXME: we need to check that if class size != 0,
455 * it needs to be greater than the class calculated size.
456 * If parent is a valuetype it also needs to be smaller than
457 * 1 MByte (0x100000 bytes).
458 * To do both these checks we need to load the referenced
459 * assemblies, though (the spec claims we didn't have to, bah).
462 * We need to check that the parent types have the same layout
473 verify_constant_table (MonoImage *image, GSList *list, int level)
475 MonoTableInfo *t = &image->tables [MONO_TABLE_CONSTANT];
476 guint32 cols [MONO_CONSTANT_SIZE];
478 GHashTable *dups = g_hash_table_new (NULL, NULL);
480 for (i = 0; i < t->rows; ++i) {
481 mono_metadata_decode_row (t, i, cols, MONO_CONSTANT_SIZE);
483 if (level & MONO_VERIFY_ERROR)
484 if (g_hash_table_lookup (dups, GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT])))
485 ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is duplicated in Constant row %d", cols [MONO_CONSTANT_PARENT], i + 1));
486 g_hash_table_insert (dups, GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT]),
487 GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT]));
489 switch (cols [MONO_CONSTANT_TYPE]) {
490 case MONO_TYPE_U1: /* LAMESPEC: it says I1...*/
494 if (level & MONO_VERIFY_CLS)
495 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));
496 case MONO_TYPE_BOOLEAN:
504 case MONO_TYPE_STRING:
505 case MONO_TYPE_CLASS:
508 if (level & MONO_VERIFY_ERROR)
509 ADD_ERROR (list, g_strdup_printf ("Type 0x%x is invalid in Constant row %d", cols [MONO_CONSTANT_TYPE], i + 1));
511 if (level & MONO_VERIFY_ERROR) {
512 value = cols [MONO_CONSTANT_PARENT] >> MONO_HASCONSTANT_BITS;
513 switch (cols [MONO_CONSTANT_PARENT] & MONO_HASCONSTANT_MASK) {
514 case MONO_HASCONSTANT_FIEDDEF:
515 if (value > image->tables [MONO_TABLE_FIELD].rows)
516 ADD_ERROR (list, g_strdup_printf ("Parent (field) is invalid in Constant row %d", i + 1));
518 case MONO_HASCONSTANT_PARAM:
519 if (value > image->tables [MONO_TABLE_PARAM].rows)
520 ADD_ERROR (list, g_strdup_printf ("Parent (param) is invalid in Constant row %d", i + 1));
522 case MONO_HASCONSTANT_PROPERTY:
523 if (value > image->tables [MONO_TABLE_PROPERTY].rows)
524 ADD_ERROR (list, g_strdup_printf ("Parent (property) is invalid in Constant row %d", i + 1));
527 ADD_ERROR (list, g_strdup_printf ("Parent is invalid in Constant row %d", i + 1));
531 if (level & MONO_VERIFY_CLS) {
533 * FIXME: verify types is consistent with the enum type
534 * is parent is an enum.
538 g_hash_table_destroy (dups);
543 verify_event_map_table (MonoImage *image, GSList *list, int level)
545 MonoTableInfo *t = &image->tables [MONO_TABLE_EVENTMAP];
546 guint32 cols [MONO_EVENT_MAP_SIZE];
547 guint32 i, last_event;
548 GHashTable *dups = g_hash_table_new (NULL, NULL);
552 for (i = 0; i < t->rows; ++i) {
553 mono_metadata_decode_row (t, i, cols, MONO_EVENT_MAP_SIZE);
554 if (level & MONO_VERIFY_ERROR)
555 if (g_hash_table_lookup (dups, GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT])))
556 ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is duplicated in Event Map row %d", cols [MONO_EVENT_MAP_PARENT], i + 1));
557 g_hash_table_insert (dups, GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT]),
558 GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT]));
559 if (level & MONO_VERIFY_ERROR) {
560 if (cols [MONO_EVENT_MAP_PARENT] > image->tables [MONO_TABLE_TYPEDEF].rows)
561 ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is invalid in Event Map row %d", cols [MONO_EVENT_MAP_PARENT], i + 1));
562 if (cols [MONO_EVENT_MAP_EVENTLIST] > image->tables [MONO_TABLE_EVENT].rows)
563 ADD_ERROR (list, g_strdup_printf ("EventList 0x%08x is invalid in Event Map row %d", cols [MONO_EVENT_MAP_EVENTLIST], i + 1));
565 if (cols [MONO_EVENT_MAP_EVENTLIST] <= last_event)
566 ADD_ERROR (list, g_strdup_printf ("EventList overlap in Event Map row %d", i + 1));
567 last_event = cols [MONO_EVENT_MAP_EVENTLIST];
571 g_hash_table_destroy (dups);
576 verify_event_table (MonoImage *image, GSList *list, int level)
578 MonoTableInfo *t = &image->tables [MONO_TABLE_EVENT];
579 guint32 cols [MONO_EVENT_SIZE];
583 for (i = 0; i < t->rows; ++i) {
584 mono_metadata_decode_row (t, i, cols, MONO_EVENT_SIZE);
586 if (cols [MONO_EVENT_FLAGS] & ~(EVENT_SPECIALNAME|EVENT_RTSPECIALNAME)) {
587 if (level & MONO_VERIFY_ERROR)
588 ADD_ERROR (list, g_strdup_printf ("Flags 0x%04x invalid in Event row %d", cols [MONO_EVENT_FLAGS], i + 1));
590 if (!(p = is_valid_string (image, cols [MONO_EVENT_NAME], TRUE))) {
591 if (level & MONO_VERIFY_ERROR)
592 ADD_ERROR (list, g_strdup_printf ("Invalid name in Event row %d", i + 1));
594 if (level & MONO_VERIFY_CLS) {
595 if (!is_valid_cls_ident (p))
596 ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Invalid CLS name '%s` in Event row %d", p, i + 1));
600 if (level & MONO_VERIFY_ERROR && cols [MONO_EVENT_TYPE]) {
601 value = cols [MONO_EVENT_TYPE] >> MONO_TYPEDEFORREF_BITS;
602 switch (cols [MONO_EVENT_TYPE] & MONO_TYPEDEFORREF_MASK) {
603 case MONO_TYPEDEFORREF_TYPEDEF:
604 if (!value || value > image->tables [MONO_TABLE_TYPEDEF].rows)
605 ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
607 case MONO_TYPEDEFORREF_TYPEREF:
608 if (!value || value > image->tables [MONO_TABLE_TYPEREF].rows)
609 ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
611 case MONO_TYPEDEFORREF_TYPESPEC:
612 if (!value || value > image->tables [MONO_TABLE_TYPESPEC].rows)
613 ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
616 ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
620 * FIXME: check that there is 1 add and remove row in methodsemantics
621 * and 0 or 1 raise and 0 or more other (maybe it's better to check for
622 * these while checking methodsemantics).
623 * check for duplicated names for the same type [ERROR]
624 * check for CLS duplicate names for the same type [CLS]
631 verify_field_table (MonoImage *image, GSList *list, int level)
633 MonoTableInfo *t = &image->tables [MONO_TABLE_FIELD];
634 guint32 cols [MONO_FIELD_SIZE];
638 for (i = 0; i < t->rows; ++i) {
639 mono_metadata_decode_row (t, i, cols, MONO_FIELD_SIZE);
641 * Check this field has only one owner and that the owner is not
642 * an interface (done in verify_typedef_table() )
644 flags = cols [MONO_FIELD_FLAGS];
645 switch (flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) {
646 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
647 case FIELD_ATTRIBUTE_PRIVATE:
648 case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
649 case FIELD_ATTRIBUTE_ASSEMBLY:
650 case FIELD_ATTRIBUTE_FAMILY:
651 case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
652 case FIELD_ATTRIBUTE_PUBLIC:
655 if (level & MONO_VERIFY_ERROR)
656 ADD_ERROR (list, g_strdup_printf ("Invalid access mask in Field row %d", i + 1));
659 if (level & MONO_VERIFY_ERROR) {
660 if ((flags & FIELD_ATTRIBUTE_LITERAL) && (flags & FIELD_ATTRIBUTE_INIT_ONLY))
661 ADD_ERROR (list, g_strdup_printf ("Literal and InitOnly cannot be both set in Field row %d", i + 1));
662 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
663 ADD_ERROR (list, g_strdup_printf ("Literal needs also Static set in Field row %d", i + 1));
664 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
665 ADD_ERROR (list, g_strdup_printf ("RTSpecialName needs also SpecialName set in Field row %d", i + 1));
667 * FIXME: check there is only one owner in the respective table.
668 * if (flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
669 * if (flags & FIELD_ATTRIBUTE_HAS_DEFAULT)
670 * if (flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA)
673 if (!(p = is_valid_string (image, cols [MONO_FIELD_NAME], TRUE))) {
674 if (level & MONO_VERIFY_ERROR)
675 ADD_ERROR (list, g_strdup_printf ("Invalid name in Field row %d", i + 1));
677 if (level & MONO_VERIFY_CLS) {
678 if (!is_valid_cls_ident (p))
679 ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Invalid CLS name '%s` in Field row %d", p, i + 1));
684 * if owner is module needs to be static, access mask needs to be compilercontrolled,
685 * public or private (not allowed in cls mode).
686 * if owner is an enum ...
695 verify_file_table (MonoImage *image, GSList *list, int level)
697 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
698 guint32 cols [MONO_FILE_SIZE];
701 GHashTable *dups = g_hash_table_new (g_str_hash, g_str_equal);
703 for (i = 0; i < t->rows; ++i) {
704 mono_metadata_decode_row (t, i, cols, MONO_FILE_SIZE);
705 if (level & MONO_VERIFY_ERROR) {
706 if (cols [MONO_FILE_FLAGS] != FILE_CONTAINS_METADATA && cols [MONO_FILE_FLAGS] != FILE_CONTAINS_NO_METADATA)
707 ADD_ERROR (list, g_strdup_printf ("Invalid flags in File row %d", i + 1));
708 if (!is_valid_blob (image, cols [MONO_FILE_HASH_VALUE], TRUE))
709 ADD_ERROR (list, g_strdup_printf ("File hash value in row %d is invalid or not null and empty", i + 1));
711 if (!(p = is_valid_string (image, cols [MONO_FILE_NAME], TRUE))) {
712 if (level & MONO_VERIFY_ERROR)
713 ADD_ERROR (list, g_strdup_printf ("Invalid name in File row %d", i + 1));
715 if (level & MONO_VERIFY_ERROR) {
716 if (!is_valid_filename (p))
717 ADD_ERROR (list, g_strdup_printf ("Invalid name '%s` in File row %d", p, i + 1));
718 else if (g_hash_table_lookup (dups, p)) {
719 ADD_ERROR (list, g_strdup_printf ("Duplicate name '%s` in File row %d", p, i + 1));
721 g_hash_table_insert (dups, (gpointer)p, (gpointer)p);
725 * FIXME: I don't understand what this means:
726 * If this module contains a row in the Assembly table (that is, if this module "holds the manifest")
727 * then there shall not be any row in the File table for this module - i.e., no self-reference [ERROR]
731 if (level & MONO_VERIFY_WARNING) {
732 if (!t->rows && image->tables [MONO_TABLE_EXPORTEDTYPE].rows)
733 ADD_WARN (list, MONO_VERIFY_WARNING, g_strdup ("ExportedType table should be empty if File table is empty"));
735 g_hash_table_destroy (dups);
740 verify_moduleref_table (MonoImage *image, GSList *list, int level)
742 MonoTableInfo *t = &image->tables [MONO_TABLE_MODULEREF];
743 MonoTableInfo *tfile = &image->tables [MONO_TABLE_FILE];
744 guint32 cols [MONO_MODULEREF_SIZE];
746 guint32 found, i, j, value;
747 GHashTable *dups = g_hash_table_new (g_str_hash, g_str_equal);
749 for (i = 0; i < t->rows; ++i) {
750 mono_metadata_decode_row (t, i, cols, MONO_MODULEREF_SIZE);
751 if (!(p = is_valid_string (image, cols [MONO_MODULEREF_NAME], TRUE))) {
752 if (level & MONO_VERIFY_ERROR)
753 ADD_ERROR (list, g_strdup_printf ("Invalid name in ModuleRef row %d", i + 1));
755 if (level & MONO_VERIFY_ERROR) {
756 if (!is_valid_filename (p))
757 ADD_ERROR (list, g_strdup_printf ("Invalid name '%s` in ModuleRef row %d", p, i + 1));
758 else if (g_hash_table_lookup (dups, p)) {
759 ADD_WARN (list, MONO_VERIFY_WARNING, g_strdup_printf ("Duplicate name '%s` in ModuleRef row %d", p, i + 1));
760 g_hash_table_insert (dups, (gpointer)p, (gpointer)p);
762 for (j = 0; j < tfile->rows; ++j) {
763 value = mono_metadata_decode_row_col (tfile, j, MONO_FILE_NAME);
764 if ((pf = is_valid_string (image, value, TRUE)))
765 if (strcmp (p, pf) == 0) {
771 ADD_ERROR (list, g_strdup_printf ("Name '%s` in ModuleRef row %d doesn't have a match in File table", p, i + 1));
776 g_hash_table_destroy (dups);
781 verify_standalonesig_table (MonoImage *image, GSList *list, int level)
783 MonoTableInfo *t = &image->tables [MONO_TABLE_STANDALONESIG];
784 guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE];
788 for (i = 0; i < t->rows; ++i) {
789 mono_metadata_decode_row (t, i, cols, MONO_STAND_ALONE_SIGNATURE_SIZE);
790 if (level & MONO_VERIFY_ERROR) {
791 if (!is_valid_blob (image, cols [MONO_STAND_ALONE_SIGNATURE], TRUE)) {
792 ADD_ERROR (list, g_strdup_printf ("Signature is invalid in StandAloneSig row %d", i + 1));
794 p = mono_metadata_blob_heap (image, cols [MONO_STAND_ALONE_SIGNATURE]);
795 /* FIXME: check it's a valid locals or method sig.*/
803 mono_image_verify_tables (MonoImage *image, int level)
805 GSList *error_list = NULL;
807 error_list = verify_assembly_table (image, error_list, level);
809 * AssemblyOS, AssemblyProcessor, AssemblyRefOs and
810 * AssemblyRefProcessor should be ignored,
811 * though we may want to emit a warning, since it should not
812 * be present in a PE file.
814 error_list = verify_assemblyref_table (image, error_list, level);
815 error_list = verify_class_layout_table (image, error_list, level);
816 error_list = verify_constant_table (image, error_list, level);
818 * cutom attribute, declsecurity
820 error_list = verify_event_map_table (image, error_list, level);
821 error_list = verify_event_table (image, error_list, level);
822 error_list = verify_field_table (image, error_list, level);
823 error_list = verify_file_table (image, error_list, level);
824 error_list = verify_moduleref_table (image, error_list, level);
825 error_list = verify_standalonesig_table (image, error_list, level);
827 return g_slist_reverse (error_list);
832 bin_num_table [TYPE_MAX] [TYPE_MAX] = {
833 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
834 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_COMPLEX, TYPE_INV, TYPE_INV},
835 {TYPE_INV, TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
836 {TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_COMPLEX, TYPE_INV, TYPE_INV},
837 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV, TYPE_INV},
838 {TYPE_INV, TYPE_COMPLEX, TYPE_INV, TYPE_COMPLEX, TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_INV},
839 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
840 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV}
845 TYPE_INV, TYPE_I4, TYPE_I8, TYPE_PTR, TYPE_R8, TYPE_INV, TYPE_INV, TYPE_INV
848 /* reduce the size of this table */
850 bin_int_table [TYPE_MAX] [TYPE_MAX] = {
851 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
852 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
853 {TYPE_INV, TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
854 {TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
855 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
856 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
857 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
858 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV}
862 bin_comp_table [TYPE_MAX] [TYPE_MAX] = {
864 {0, 1, 0, 1, 0, 0, 0, 0},
865 {0, 0, 1, 0, 0, 0, 0, 0},
866 {0, 1, 0, 1, 0, 2, 0, 0},
867 {0, 0, 0, 0, 1, 0, 0, 0},
868 {0, 0, 0, 2, 0, 1, 0, 0},
869 {0, 0, 0, 0, 0, 0, 3, 0},
870 {0, 0, 0, 0, 0, 0, 0, 0},
873 /* reduce the size of this table */
875 shift_table [TYPE_MAX] [TYPE_MAX] = {
876 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
877 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
878 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
879 {TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
880 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
881 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
882 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
883 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV}
888 TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I8, TYPE_PTR, TYPE_R8, TYPE_R8, TYPE_COMPLEX
893 TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I8, TYPE_PTR, TYPE_R8, TYPE_R8, TYPE_COMPLEX
896 #define ADD_INVALID(list,msg) \
898 MonoVerifyInfo *vinfo = g_new (MonoVerifyInfo, 1); \
899 vinfo->status = MONO_VERIFY_ERROR; \
900 vinfo->message = (msg); \
901 (list) = g_slist_prepend ((list), vinfo); \
902 /*G_BREAKPOINT ();*/ \
906 #define CHECK_STACK_UNDERFLOW(num) \
908 if (cur_stack < (num)) \
909 ADD_INVALID (list, g_strdup_printf ("Stack underflow at 0x%04x (%d items instead of %d)", ip_offset, cur_stack, (num))); \
912 #define CHECK_STACK_OVERFLOW() \
914 if (cur_stack >= max_stack) \
915 ADD_INVALID (list, g_strdup_printf ("Maxstack exceeded at 0x%04x", ip_offset)); \
920 type_to_eval_stack_type (MonoType *type, ILStackDesc *stack, int take_addr) {
924 if (type->byref || take_addr) { /* fix double addr issue */
925 stack->stype = TYPE_COMPLEX;
933 case MONO_TYPE_BOOLEAN:
939 stack->stype = TYPE_I4;
944 stack->stype = TYPE_PTR;
946 case MONO_TYPE_CLASS:
947 case MONO_TYPE_STRING:
948 case MONO_TYPE_OBJECT:
949 case MONO_TYPE_SZARRAY:
950 case MONO_TYPE_ARRAY:
951 stack->stype = TYPE_COMPLEX;
955 stack->stype = TYPE_I8;
959 stack->stype = TYPE_R8;
961 case MONO_TYPE_VALUETYPE:
962 if (type->data.klass->enumtype) {
963 t = type->data.klass->enum_basetype->type;
966 stack->stype = TYPE_COMPLEX;
970 g_error ("unknown type %02x in eval stack type", type->type);
976 type_from_op (int ins, ILStackDesc *arg) {
984 /* FIXME: check unverifiable args for TYPE_COMPLEX */
985 return arg->stype = bin_num_table [arg->stype] [arg [1].stype];
991 return arg->stype = bin_int_table [arg->stype] [arg [1].stype];
995 return arg->stype = shift_table [arg->stype] [arg [1].stype];
1016 /* FIXME: handle some specifics with ins->next->type */
1017 return bin_comp_table [arg->stype] [arg [1].stype] ? TYPE_I4: TYPE_INV;
1020 case 256+CEE_CGT_UN:
1022 case 256+CEE_CLT_UN:
1023 return arg->stype = bin_comp_table [arg->stype] [arg [1].stype] ? TYPE_I4: TYPE_INV;
1026 return arg->stype = neg_table [arg->stype];
1028 if (arg->stype >= TYPE_I4 && arg->stype <= TYPE_PTR)
1031 return arg->stype = TYPE_INV;
1038 case CEE_CONV_OVF_I1:
1039 case CEE_CONV_OVF_U1:
1040 case CEE_CONV_OVF_I2:
1041 case CEE_CONV_OVF_U2:
1042 case CEE_CONV_OVF_I4:
1043 case CEE_CONV_OVF_U4:
1044 case CEE_CONV_OVF_I1_UN:
1045 case CEE_CONV_OVF_U1_UN:
1046 case CEE_CONV_OVF_I2_UN:
1047 case CEE_CONV_OVF_U2_UN:
1048 case CEE_CONV_OVF_I4_UN:
1049 case CEE_CONV_OVF_U4_UN:
1050 if (arg->stype == TYPE_INV || arg->stype >= TYPE_COMPLEX)
1051 return arg->stype = TYPE_INV;
1052 return arg->stype = TYPE_I4;
1055 case CEE_CONV_OVF_I:
1056 case CEE_CONV_OVF_U:
1057 case CEE_CONV_OVF_I_UN:
1058 case CEE_CONV_OVF_U_UN:
1059 if (arg->stype == TYPE_INV || arg->stype == TYPE_COMPLEX)
1060 return arg->stype = TYPE_INV;
1061 return arg->stype = TYPE_PTR;
1064 case CEE_CONV_OVF_I8:
1065 case CEE_CONV_OVF_U8:
1066 case CEE_CONV_OVF_I8_UN:
1067 case CEE_CONV_OVF_U8_UN:
1068 return arg->stype = TYPE_I8;
1071 return arg->stype = TYPE_R8;
1073 g_error ("opcode 0x%04x not handled in type from op", ins);
1080 in_any_block (MonoMethodHeader *header, guint offset)
1083 MonoExceptionClause *clause;
1085 for (i = 0; i < header->num_clauses; ++i) {
1086 clause = &header->clauses [i];
1087 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1089 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1091 if (MONO_OFFSET_IN_FILTER (clause, offset))
1098 in_same_block (MonoMethodHeader *header, guint offset, guint target)
1101 MonoExceptionClause *clause;
1103 for (i = 0; i < header->num_clauses; ++i) {
1104 clause = &header->clauses [i];
1105 if (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target))
1107 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1109 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1116 * is_valid_branch_instruction:
1118 * Verify if it's valid to perform a branch from @offset to @target.
1119 * This should be used with br and brtrue/false.
1120 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1121 * The major diferent from other similiar functions is that branching into a
1122 * finally/fault block is invalid instead of just unverifiable.
1125 is_valid_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1128 MonoExceptionClause *clause;
1130 for (i = 0; i < header->num_clauses; ++i) {
1131 clause = &header->clauses [i];
1132 /*branching into a finally block is invalid*/
1133 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) &&
1134 !MONO_OFFSET_IN_HANDLER (clause, offset) &&
1135 MONO_OFFSET_IN_HANDLER (clause, target))
1138 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1140 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1142 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1149 * is_valid_cmp_branch_instruction:
1151 * Verify if it's valid to perform a branch from @offset to @target.
1152 * This should be used with binary comparison branching instruction, like beq, bge and similars.
1153 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1155 * The major diferences from other similar functions are that most errors lead to invalid
1156 * code and only branching out of finally, filter or fault clauses is unverifiable.
1159 is_valid_cmp_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1162 MonoExceptionClause *clause;
1164 for (i = 0; i < header->num_clauses; ++i) {
1165 clause = &header->clauses [i];
1166 /*branching out of a handler or finally*/
1167 if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE &&
1168 MONO_OFFSET_IN_HANDLER (clause, offset) &&
1169 !MONO_OFFSET_IN_HANDLER (clause, target))
1172 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1174 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1176 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1183 * A leave can't escape a finally block
1186 is_correct_leave (MonoMethodHeader *header, guint offset, guint target)
1189 MonoExceptionClause *clause;
1191 for (i = 0; i < header->num_clauses; ++i) {
1192 clause = &header->clauses [i];
1193 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY && MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
1195 if (MONO_OFFSET_IN_FILTER (clause, offset))
1202 * A rethrow can't happen outside of a catch handler.
1205 is_correct_rethrow (MonoMethodHeader *header, guint offset)
1208 MonoExceptionClause *clause;
1210 for (i = 0; i < header->num_clauses; ++i) {
1211 clause = &header->clauses [i];
1212 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1214 if (MONO_OFFSET_IN_FILTER (clause, offset))
1221 * An endfinally can't happen outside of a finally/fault handler.
1224 is_correct_endfinally (MonoMethodHeader *header, guint offset)
1227 MonoExceptionClause *clause;
1229 for (i = 0; i < header->num_clauses; ++i) {
1230 clause = &header->clauses [i];
1231 if (MONO_OFFSET_IN_HANDLER (clause, offset) && (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY))
1239 * An endfilter can only happens inside a filter clause.
1240 * In non-strict mode filter is allowed inside the handler clause too
1242 static MonoExceptionClause *
1243 is_correct_endfilter (VerifyContext *ctx, guint offset)
1246 MonoExceptionClause *clause;
1248 for (i = 0; i < ctx->header->num_clauses; ++i) {
1249 clause = &ctx->header->clauses [i];
1250 if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER)
1252 if (MONO_OFFSET_IN_FILTER (clause, offset))
1254 if (!IS_STRICT_MODE (ctx) && MONO_OFFSET_IN_HANDLER (clause, offset))
1262 * Non-strict endfilter can happens inside a try block or any handler block
1265 is_unverifiable_endfilter (VerifyContext *ctx, guint offset)
1268 MonoExceptionClause *clause;
1270 for (i = 0; i < ctx->header->num_clauses; ++i) {
1271 clause = &ctx->header->clauses [i];
1272 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1280 can_merge_stack (ILCodeDesc *a, ILCodeDesc *b)
1282 if (!b->flags & IL_CODE_FLAG_SEEN) {
1283 b->flags |= IL_CODE_FLAG_SEEN;
1288 if (a->size != b->size)
1295 is_valid_bool_arg (ILStackDesc *arg)
1297 if (IS_MANAGED_POINTER (arg->stype))
1299 switch (arg->stype) {
1302 case TYPE_NATIVE_INT:
1306 g_assert (arg->type);
1307 switch (arg->type->type) {
1308 case MONO_TYPE_CLASS:
1309 case MONO_TYPE_STRING:
1310 case MONO_TYPE_OBJECT:
1311 case MONO_TYPE_SZARRAY:
1312 case MONO_TYPE_ARRAY:
1313 case MONO_TYPE_FNPTR:
1316 case MONO_TYPE_GENERICINST:
1317 /*We need to check if the container class
1318 * of the generic type is a valuetype, iow:
1319 * is it a "class Foo<T>" or a "struct Foo<T>"?
1321 return !arg->type->data.generic_class->container_class->valuetype;
1330 can_store_type (ILStackDesc *arg, MonoType *type)
1333 if (type->byref && arg->stype != TYPE_COMPLEX)
1337 case MONO_TYPE_VOID:
1341 case MONO_TYPE_BOOLEAN:
1344 case MONO_TYPE_CHAR:
1347 if (arg->stype == TYPE_I4 || arg->stype == TYPE_PTR)
1354 case MONO_TYPE_CLASS:
1355 case MONO_TYPE_STRING:
1356 case MONO_TYPE_OBJECT:
1357 case MONO_TYPE_SZARRAY:
1358 case MONO_TYPE_ARRAY:
1359 return TRUE; /* FIXME */
1362 if (arg->stype == TYPE_I8)
1367 if (arg->stype == TYPE_R8)
1370 case MONO_TYPE_VALUETYPE:
1371 if (type->data.klass->enumtype) {
1372 t = type->data.klass->enum_basetype->type;
1375 if (arg->type->data.klass != type->data.klass)
1380 g_error ("unknown type %02x in store type", type->type);
1386 stind_type (int op, int type) {
1389 return type == TYPE_COMPLEX;
1393 return type == TYPE_I4;
1395 return type == TYPE_I8;
1398 return type == TYPE_R8;
1400 g_assert_not_reached ();
1406 /*Type manipulation helper*/
1408 /*Returns the byref version of the supplied MonoType*/
1410 mono_type_get_type_byref (MonoType *type)
1414 return &mono_class_from_mono_type (type)->this_arg;
1418 /*Returns the byval version of the supplied MonoType*/
1420 mono_type_get_type_byval (MonoType *type)
1424 return &mono_class_from_mono_type (type)->byval_arg;
1428 mono_type_from_stack_slot (ILStackDesc *slot)
1430 if (IS_MANAGED_POINTER (slot->stype))
1431 return mono_type_get_type_byref (slot->type);
1435 /*Stack manipulation code*/
1438 stack_init (VerifyContext *ctx, ILCodeDesc *state)
1440 if (state->flags & IL_CODE_FLAG_STACK_INITED)
1443 state->flags |= IL_CODE_FLAG_STACK_INITED;
1445 state->stack = g_new0 (ILStackDesc, ctx->max_stack);
1449 stack_copy (ILCodeDesc *to, ILCodeDesc *from)
1451 to->size = from->size;
1452 memcpy (to->stack, from->stack, sizeof (ILStackDesc) * from->size);
1456 copy_stack_value (ILStackDesc *to, ILStackDesc *from)
1458 to->stype = from->stype;
1459 to->type = from->type;
1463 check_underflow (VerifyContext *ctx, int size)
1465 if (ctx->eval.size < size) {
1466 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack underflow, required %d, but have %d at 0x%04x", size, ctx->eval.size, ctx->ip_offset));
1473 check_overflow (VerifyContext *ctx)
1475 if (ctx->eval.size >= ctx->max_stack) {
1476 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have stack-depth %d at 0x%04x", ctx->eval.size + 1, ctx->ip_offset));
1483 check_unmanaged_pointer (VerifyContext *ctx, ILStackDesc *value)
1485 if (value->stype == TYPE_PTR) {
1486 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1493 check_unverifiable_type (VerifyContext *ctx, MonoType *type)
1495 if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
1496 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1503 static ILStackDesc *
1504 stack_push (VerifyContext *ctx)
1506 return & ctx->eval.stack [ctx->eval.size++];
1509 static ILStackDesc *
1510 stack_push_val (VerifyContext *ctx, int stype, MonoType *type)
1512 ILStackDesc *top = stack_push (ctx);
1518 static ILStackDesc *
1519 stack_pop (VerifyContext *ctx)
1521 return ctx->eval.stack + --ctx->eval.size;
1524 static inline ILStackDesc *
1525 stack_top (VerifyContext *ctx)
1527 return ctx->eval.stack + (ctx->eval.size - 1);
1530 static inline ILStackDesc *
1531 stack_get (VerifyContext *ctx, int distance)
1533 return ctx->eval.stack + (ctx->eval.size - distance - 1);
1536 /* Returns the MonoType associated with the token, or NULL if it is invalid.
1538 * A boxable type can be either a reference or value type, but cannot be a byref type or an unmanaged pointer
1541 get_boxable_mono_type (VerifyContext* ctx, int token)
1543 MonoType *type = mono_type_get_full (ctx->image, token, ctx->generic_context);
1546 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
1550 if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
1551 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type at 0x%04x", ctx->ip_offset));
1555 if (type->type == MONO_TYPE_TYPEDBYREF) {
1556 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid use of typedbyref at 0x%04x", ctx->ip_offset));
1560 check_unverifiable_type (ctx, type);
1565 /*operation result tables */
1567 static const unsigned char bin_op_table [TYPE_MAX][TYPE_MAX] = {
1568 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1569 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1570 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1571 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1572 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1573 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1576 static const unsigned char add_table [TYPE_MAX][TYPE_MAX] = {
1577 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1578 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1579 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1580 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1581 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1582 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1585 static const unsigned char sub_table [TYPE_MAX][TYPE_MAX] = {
1586 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1587 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1588 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1589 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1590 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1591 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1594 static const unsigned char int_bin_op_table [TYPE_MAX][TYPE_MAX] = {
1595 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1596 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1597 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1598 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1599 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1600 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1603 static const unsigned char shift_op_table [TYPE_MAX][TYPE_MAX] = {
1604 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1605 {TYPE_I8, TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV},
1606 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1607 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1608 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1609 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1612 static const unsigned char cmp_br_op [TYPE_MAX][TYPE_MAX] = {
1613 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1614 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1615 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1616 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1617 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV},
1618 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1621 static const unsigned char cmp_br_eq_op [TYPE_MAX][TYPE_MAX] = {
1622 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1623 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1624 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV},
1625 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1626 {TYPE_INV, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_I4, TYPE_INV},
1627 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4},
1632 dump_stack_value (ILStackDesc *value)
1634 printf ("[(%d)(%d)", value->type->type, value->stype);
1636 if (value->stype & CMMP_MASK)
1637 printf ("Controled Mutability MP: ");
1639 if (IS_MANAGED_POINTER (value->stype))
1640 printf ("Managed Pointer to: ");
1642 switch (UNMASK_TYPE (value->stype)) {
1644 printf ("invalid type]");
1652 case TYPE_NATIVE_INT:
1653 printf ("native int]");
1656 printf ("float64]");
1659 printf ("unmanaged pointer]");
1662 switch (value->type->type) {
1663 case MONO_TYPE_CLASS:
1664 case MONO_TYPE_VALUETYPE:
1665 printf ("complex] (%s)", value->type->data.klass->name);
1667 case MONO_TYPE_STRING:
1668 printf ("complex] (string)");
1670 case MONO_TYPE_OBJECT:
1671 printf ("complex] (object)");
1673 case MONO_TYPE_SZARRAY:
1674 printf ("complex] (%s [])", value->type->data.klass->name);
1676 case MONO_TYPE_ARRAY:
1677 printf ("complex] (%s [%d %d %d])",
1678 value->type->data.array->eklass->name,
1679 value->type->data.array->rank,
1680 value->type->data.array->numsizes,
1681 value->type->data.array->numlobounds);
1683 case MONO_TYPE_GENERICINST:
1684 printf ("complex] (inst of %s )", value->type->data.generic_class->container_class->name);
1687 printf ("complex] (type generic param !%d - %s) ", value->type->data.generic_param->num, value->type->data.generic_param->name);
1689 case MONO_TYPE_MVAR:
1690 printf ("complex] (method generic param !!%d - %s) ", value->type->data.generic_param->num, value->type->data.generic_param->name);
1693 printf ("unknown complex %d type]\n", value->type->type);
1694 g_assert_not_reached ();
1697 printf ("unknown stack %d type]\n", value->stype);
1698 g_assert_not_reached ();
1703 dump_stack_state (ILCodeDesc *state)
1707 printf ("(%d) ", state->size);
1708 for (i = 0; i < state->size; ++i)
1709 dump_stack_value (state->stack + i);
1714 dump_context (VerifyContext *ctx, int code_size)
1718 for (i = 0; i < code_size; ++i) {
1719 if (ctx->code [i].flags & IL_CODE_FLAG_SEEN) {
1720 printf ("opcode [%d]:\n\t", i);
1721 dump_stack_state (&ctx->code [i]);
1726 /*Returns TRUE if candidate array type can be assigned to target.
1727 *Both parameters MUST be of type MONO_TYPE_ARRAY (target->type == MONO_TYPE_ARRAY)
1730 is_array_type_compatible (MonoType *target, MonoType *candidate)
1733 MonoArrayType *left = target->data.array;
1734 MonoArrayType *right = candidate->data.array;
1736 g_assert (target->type == MONO_TYPE_ARRAY);
1737 g_assert (candidate->type == MONO_TYPE_ARRAY);
1740 if ((left->rank != right->rank) ||
1741 (left->numsizes != right->numsizes) ||
1742 (left->numlobounds != right->numlobounds))
1745 for (i = 0; i < left->numsizes; ++i)
1746 if (left->sizes [i] != right->sizes [i])
1749 for (i = 0; i < left->numlobounds; ++i)
1750 if (left->lobounds [i] != right->lobounds [i])
1753 return mono_class_is_assignable_from (left->eklass, right->eklass);
1757 get_stack_type (MonoType *type)
1760 int type_kind = type->type;
1762 mask = POINTER_MASK;
1763 /*TODO handle CMMP_MASK */
1766 switch (type_kind) {
1769 case MONO_TYPE_BOOLEAN:
1772 case MONO_TYPE_CHAR:
1775 return TYPE_I4 | mask;
1779 return TYPE_NATIVE_INT | mask;
1781 /* FIXME: the spec says that you cannot have a pointer to method pointer, do we need to check this here? */
1782 case MONO_TYPE_FNPTR:
1784 case MONO_TYPE_TYPEDBYREF:
1785 return TYPE_PTR | mask;
1787 case MONO_TYPE_CLASS:
1788 case MONO_TYPE_STRING:
1789 case MONO_TYPE_OBJECT:
1790 case MONO_TYPE_SZARRAY:
1791 case MONO_TYPE_ARRAY:
1792 case MONO_TYPE_GENERICINST:
1793 return TYPE_COMPLEX | mask;
1797 return TYPE_I8 | mask;
1801 return TYPE_R8 | mask;
1803 case MONO_TYPE_VALUETYPE:
1804 if (type->data.klass->enumtype) {
1805 type = type->data.klass->enum_basetype;
1806 type_kind = type->type;
1809 return TYPE_COMPLEX | mask;
1812 VERIFIER_DEBUG ( printf ("unknown type %02x in eval stack type\n", type->type); );
1813 g_assert_not_reached ();
1818 /* convert MonoType to ILStackDesc format (stype) */
1820 set_stack_value (ILStackDesc *stack, MonoType *type, int take_addr)
1823 int type_kind = type->type;
1825 if (type->byref || take_addr)
1826 mask = POINTER_MASK;
1827 /* TODO handle CMMP_MASK */
1832 switch (type_kind) {
1835 case MONO_TYPE_BOOLEAN:
1838 case MONO_TYPE_CHAR:
1841 stack->stype = TYPE_I4 | mask;
1845 stack->stype = TYPE_NATIVE_INT | mask;
1848 /*FIXME: Do we need to check if it's a pointer to the method pointer? The spec says it' illegal to have that.*/
1849 case MONO_TYPE_FNPTR:
1851 case MONO_TYPE_TYPEDBYREF:
1852 stack->stype = TYPE_PTR | mask;
1855 case MONO_TYPE_CLASS:
1856 case MONO_TYPE_STRING:
1857 case MONO_TYPE_OBJECT:
1858 case MONO_TYPE_SZARRAY:
1859 case MONO_TYPE_ARRAY:
1861 case MONO_TYPE_GENERICINST:
1863 case MONO_TYPE_MVAR:
1864 stack->stype = TYPE_COMPLEX | mask;
1868 stack->stype = TYPE_I8 | mask;
1872 stack->stype = TYPE_R8 | mask;
1874 case MONO_TYPE_VALUETYPE:
1875 if (type->data.klass->enumtype) {
1876 type = type->data.klass->enum_basetype;
1877 type_kind = type->type;
1880 stack->stype = TYPE_COMPLEX | mask;
1884 VERIFIER_DEBUG ( printf ("unknown type 0x%02x in eval stack type\n", type->type); );
1885 g_assert_not_reached ();
1891 * init_stack_with_value_at_exception_boundary:
1893 * Initialize the stack and push a given type.
1894 * The instruction is marked as been on the exception boundary.
1897 init_stack_with_value_at_exception_boundary (VerifyContext *ctx, ILCodeDesc *code, MonoClass *klass)
1899 stack_init (ctx, code);
1900 set_stack_value (code->stack, &klass->byval_arg, FALSE);
1902 code->flags |= IL_CODE_FLAG_WAS_TARGET;
1905 /* Generics validation stuff, should be moved to another metadata/? file */
1907 mono_is_generic_type_compatible (MonoType *target, MonoType *candidate)
1909 if (target->byref != candidate->byref)
1913 switch (target->type) {
1914 case MONO_TYPE_STRING:
1915 if (candidate->type == MONO_TYPE_STRING)
1919 case MONO_TYPE_CLASS:
1920 if (candidate->type != MONO_TYPE_CLASS)
1923 VERIFIER_DEBUG ( printf ("verifying type class %p %p\n", target->data.klass, candidate->data.klass); );
1924 return mono_class_is_assignable_from (target->data.klass, candidate->data.klass);
1926 case MONO_TYPE_OBJECT:
1927 return MONO_TYPE_IS_REFERENCE (candidate);
1929 case MONO_TYPE_SZARRAY:
1930 if (candidate->type != MONO_TYPE_SZARRAY)
1932 return mono_class_is_assignable_from (target->data.klass, candidate->data.klass);
1934 case MONO_TYPE_VALUETYPE:
1935 if (target->data.klass->enumtype) {
1936 target = target->data.klass->enum_basetype;
1939 if (candidate->type != MONO_TYPE_VALUETYPE)
1941 return candidate->data.klass == target->data.klass;
1944 case MONO_TYPE_ARRAY:
1945 if (candidate->type != MONO_TYPE_ARRAY)
1947 return is_array_type_compatible (target, candidate);
1950 VERIFIER_DEBUG ( printf ("unknown target type %d\n", target->type); );
1951 g_assert_not_reached ();
1959 mono_is_generic_instance_compatible (MonoGenericClass *target, MonoGenericClass *candidate, MonoGenericClass *root_candidate) {
1960 MonoGenericContainer *container;
1963 VERIFIER_DEBUG ( printf ("candidate container %p\n", candidate->container_class->generic_container); );
1964 if (target->container_class != candidate->container_class) {
1965 MonoType *param_class;
1966 MonoClass *cand_class;
1967 VERIFIER_DEBUG ( printf ("generic class != target\n"); );
1968 param_class = candidate->context.class_inst->type_argv [0];
1969 VERIFIER_DEBUG ( printf ("param 0 %d\n", param_class->type); );
1970 cand_class = candidate->container_class;
1972 /* We must check if it's an interface type*/
1973 if (MONO_CLASS_IS_INTERFACE (target->container_class)) {
1974 VERIFIER_DEBUG ( printf ("generic type is an interface\n"); );
1977 int iface_count = cand_class->interface_count;
1978 MonoClass **ifaces = cand_class->interfaces;
1980 VERIFIER_DEBUG ( printf ("type has %d interfaces\n", iface_count); );
1981 for (i = 0; i< iface_count; ++i) {
1982 MonoClass *ifc = ifaces[i];
1983 VERIFIER_DEBUG ( printf ("analysing %s\n", ifc->name); );
1984 if (ifc->generic_class) {
1985 VERIFIER_DEBUG ( printf ("interface has generic info\n"); );
1987 if (mono_is_generic_instance_compatible (target, ifc->generic_class, root_candidate)) {
1988 VERIFIER_DEBUG ( printf ("we got compatible stuff!\n"); );
1993 cand_class = cand_class->parent;
1994 } while (cand_class);
1996 VERIFIER_DEBUG ( printf ("don't implements an interface\n"); );
1999 VERIFIER_DEBUG ( printf ("verifying upper classes\n"); );
2001 cand_class = cand_class->parent;
2003 while (cand_class) {
2004 VERIFIER_DEBUG ( printf ("verifying parent class name %s\n", cand_class->name); );
2005 if (cand_class->generic_class) {
2006 VERIFIER_DEBUG ( printf ("super type has generic context\n"); );
2008 /* TODO break loop if target->container_class == cand_class->generic_class->container_class */
2009 return mono_is_generic_instance_compatible (target, cand_class->generic_class, root_candidate);
2011 VERIFIER_DEBUG ( printf ("super class has no generic context\n"); );
2012 cand_class = cand_class->parent;
2018 /* now we verify if the instantiations are compatible*/
2019 if (target->context.class_inst == candidate->context.class_inst) {
2020 VERIFIER_DEBUG ( printf ("generic types are compatible, both have the same instantiation\n"); );
2024 if (target->context.class_inst->type_argc != candidate->context.class_inst->type_argc) {
2025 VERIFIER_DEBUG ( printf ("generic instantiations with different arg counts\n"); );
2029 //verify if open instance -- none should be
2031 container = target->container_class->generic_container;
2033 for (i = 0; i < container->type_argc; ++i) {
2034 MonoGenericParam *param = container->type_params + i;
2035 MonoType *target_type = target->context.class_inst->type_argv [i];
2036 MonoType *candidate_type = candidate->context.class_inst->type_argv [i];
2037 /* We resolve TYPE_VAR types before proceeding */
2039 if (candidate_type->type == MONO_TYPE_VAR) {
2040 MonoGenericParam *var_param = candidate_type->data.generic_param;
2041 candidate_type = root_candidate->context.class_inst->type_argv [var_param->num];
2044 if ((param->flags & GENERIC_PARAMETER_ATTRIBUTE_VARIANCE_MASK) == 0) {
2045 VERIFIER_DEBUG ( printf ("generic type have no variance flag, checking each type %d %d \n",target_type->type, candidate_type->type); );
2047 if (!mono_metadata_type_equal (target_type, candidate_type))
2050 VERIFIER_DEBUG ( printf ("generic type has variance flag, need to perform deeper check\n"); );
2051 /* first we check if they are the same kind */
2052 /* byref generic params are forbiden, but better safe than sorry.*/
2054 if ((param->flags & GENERIC_PARAMETER_ATTRIBUTE_COVARIANT) == GENERIC_PARAMETER_ATTRIBUTE_COVARIANT) {
2055 if (!mono_is_generic_type_compatible (target_type, candidate_type))
2057 /* the attribute must be contravariant */
2058 } else if (!mono_is_generic_type_compatible (candidate_type, target_type))
2067 /*Verify if type 'candidate' can be stored in type 'target'.
2069 * If strict, check for the underlying type and not the verification stack types
2072 verify_type_compatibility_full (VerifyContext *ctx, MonoType *target, MonoType *candidate, gboolean strict)
2074 #define IS_ONE_OF3(T, A, B, C) (T == A || T == B || T == C)
2075 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
2077 VERIFIER_DEBUG ( printf ("checking type compatibility %p %p[%d][%d] %p[%d][%d]\n", ctx, target, target->type, target->byref, candidate, candidate->type, candidate->byref); );
2079 /*only one is byref */
2080 if (candidate->byref ^ target->byref) {
2081 /* converting from native int to byref*/
2082 if (get_stack_type (candidate) == TYPE_NATIVE_INT && target->byref) {
2083 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("using byref native int at 0x%04x", ctx->ip_offset));
2088 strict |= target->byref;
2091 switch (target->type) {
2094 case MONO_TYPE_BOOLEAN:
2096 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I1, MONO_TYPE_U1, MONO_TYPE_BOOLEAN);
2099 case MONO_TYPE_CHAR:
2101 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I2, MONO_TYPE_U2, MONO_TYPE_CHAR);
2103 case MONO_TYPE_U4: {
2104 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2105 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2107 return is_native_int || is_int4;
2108 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2113 return IS_ONE_OF2 (candidate->type, MONO_TYPE_I8, MONO_TYPE_U8);
2118 return candidate->type == target->type;
2119 return IS_ONE_OF2 (candidate->type, MONO_TYPE_R4, MONO_TYPE_R8);
2123 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2124 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2126 return is_native_int || is_int4;
2127 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2131 if (candidate->type != MONO_TYPE_PTR)
2133 /* check the underlying type */
2134 return verify_type_compatibility_full (ctx, target->data.type, candidate->data.type, TRUE);
2136 case MONO_TYPE_FNPTR: {
2137 MonoMethodSignature *left, *right;
2138 if (candidate->type != MONO_TYPE_FNPTR)
2141 left = mono_type_get_signature (target);
2142 right = mono_type_get_signature (candidate);
2143 return mono_metadata_signature_equal (left, right) && left->call_convention == right->call_convention;
2146 case MONO_TYPE_GENERICINST: {
2147 MonoGenericClass *left;
2148 MonoGenericClass *right;
2149 if (candidate->type != MONO_TYPE_GENERICINST)
2151 left = target->data.generic_class;
2152 right = candidate->data.generic_class;
2154 return mono_is_generic_instance_compatible (left, right, right);
2157 case MONO_TYPE_STRING:
2158 return candidate->type == MONO_TYPE_STRING;
2160 case MONO_TYPE_CLASS:
2161 return mono_class_is_assignable_from (target->data.klass, mono_class_from_mono_type (candidate));
2163 case MONO_TYPE_OBJECT:
2164 return MONO_TYPE_IS_REFERENCE (candidate);
2166 case MONO_TYPE_SZARRAY: {
2169 if (candidate->type != MONO_TYPE_SZARRAY)
2172 left = target->data.klass;
2173 right = candidate->data.klass;
2174 return mono_class_is_assignable_from(left, right);
2177 case MONO_TYPE_ARRAY:
2178 if (candidate->type != MONO_TYPE_ARRAY)
2180 return is_array_type_compatible (target, candidate);
2182 //TODO verify aditional checks that needs to be done
2183 case MONO_TYPE_TYPEDBYREF:
2184 return candidate->type == MONO_TYPE_TYPEDBYREF;
2186 case MONO_TYPE_VALUETYPE:
2187 if (target->data.klass->enumtype) {
2188 target = target->data.klass->enum_basetype;
2191 if (candidate->type != MONO_TYPE_VALUETYPE)
2193 return target->data.klass == candidate->data.klass;
2197 if (candidate->type != MONO_TYPE_VAR)
2199 return candidate->data.generic_param->num == target->data.generic_param->num;
2201 case MONO_TYPE_MVAR:
2202 if (candidate->type != MONO_TYPE_MVAR)
2204 return candidate->data.generic_param->num == target->data.generic_param->num;
2207 VERIFIER_DEBUG ( printf ("unknown store type %d\n", target->type); );
2208 g_assert_not_reached ();
2217 verify_type_compatibility (VerifyContext *ctx, MonoType *target, MonoType *candidate)
2219 return verify_type_compatibility_full (ctx, target, candidate, FALSE);
2224 verify_stack_type_compatibility (VerifyContext *ctx, MonoType *type, ILStackDesc *stack)
2226 return verify_type_compatibility_full (ctx, type, mono_type_from_stack_slot (stack), FALSE);
2229 /* implement the opcode checks*/
2231 push_arg (VerifyContext *ctx, unsigned int arg, int take_addr)
2233 if (arg >= ctx->max_args) {
2235 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2237 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2238 if (check_overflow (ctx)) //FIXME: what sane value could we ever push?
2239 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
2241 } else if (check_overflow (ctx)) {
2242 /*We must let the value be pushed, otherwise we would get an underflow error*/
2243 check_unverifiable_type (ctx, ctx->params [arg]);
2244 if (ctx->params [arg]->byref && take_addr)
2245 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2246 set_stack_value (stack_push (ctx), ctx->params [arg], take_addr);
2251 push_local (VerifyContext *ctx, guint32 arg, int take_addr)
2253 if (arg >= ctx->num_locals) {
2254 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local %d", arg + 1));
2255 } else if (check_overflow (ctx)) {
2256 /*We must let the value be pushed, otherwise we would get an underflow error*/
2257 check_unverifiable_type (ctx, ctx->locals [arg]);
2258 if (ctx->locals [arg]->byref && take_addr)
2259 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2261 set_stack_value (stack_push (ctx), ctx->locals [arg], take_addr);
2266 store_arg (VerifyContext *ctx, guint32 arg)
2270 if (arg >= ctx->max_args) {
2271 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", arg + 1, ctx->ip_offset));
2272 check_underflow (ctx, 1);
2277 if (check_underflow (ctx, 1)) {
2278 value = stack_pop (ctx);
2279 if (!verify_stack_type_compatibility (ctx, ctx->params [arg], value)) {
2280 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in argument store at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
2286 store_local (VerifyContext *ctx, guint32 arg)
2289 if (arg >= ctx->num_locals) {
2290 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", arg + 1, ctx->ip_offset));
2294 /*TODO verify definite assigment */
2295 if (check_underflow (ctx, 1)) {
2296 value = stack_pop(ctx);
2297 if (!verify_stack_type_compatibility (ctx, ctx->locals [arg], value)) {
2298 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in local store at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
2304 do_binop (VerifyContext *ctx, unsigned int opcode, const unsigned char table [TYPE_MAX][TYPE_MAX])
2307 int idxa, idxb, complexMerge = 0;
2310 if (!check_underflow (ctx, 2))
2312 a = stack_get (ctx, 1);
2313 b = stack_top (ctx);
2316 if (IS_MANAGED_POINTER (idxa)) {
2322 if (IS_MANAGED_POINTER (idxb)) {
2329 res = table [idxa][idxb];
2331 VERIFIER_DEBUG ( printf ("binop res %d\n", res); );
2332 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
2335 if (res == TYPE_INV) {
2336 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Binary instruction applyed to ill formed stack (%s x %s)", type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)]));
2340 if (res & NON_VERIFIABLE_RESULT) {
2341 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Binary instruction is not verifiable (%s x %s)",
2342 type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)]));
2344 res = res & ~NON_VERIFIABLE_RESULT;
2347 if (complexMerge && res == TYPE_PTR) {
2348 if (complexMerge == 1)
2349 copy_stack_value (stack_top (ctx), a);
2350 else if (complexMerge == 2)
2351 copy_stack_value (stack_top (ctx), b);
2353 * There is no need to merge the type of two pointers.
2354 * The only valid operation is subtraction, that returns a native
2355 * int as result and can be used with any 2 pointer kinds.
2356 * This is valid acording to Patition III 1.1.4
2359 stack_top (ctx)->stype = res;
2365 do_boolean_branch_op (VerifyContext *ctx, int delta)
2367 int target = ctx->ip_offset + delta;
2370 VERIFIER_DEBUG ( printf ("boolean branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
2372 if (target < 0 || target >= ctx->code_size) {
2373 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Boolean branch target out of code at 0x%04x", ctx->ip_offset));
2377 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
2379 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2382 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2386 ctx->target = target;
2388 if (!check_underflow (ctx, 1))
2391 top = stack_pop (ctx);
2392 if (!is_valid_bool_arg (top))
2393 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Argument type %s not valid for brtrue/brfalse at 0x%04x", type_names [UNMASK_TYPE (stack_get (ctx, -1)->stype)], ctx->ip_offset));
2395 check_unmanaged_pointer (ctx, top);
2400 do_branch_op (VerifyContext *ctx, signed int delta, const unsigned char table [TYPE_MAX][TYPE_MAX])
2405 int target = ctx->ip_offset + delta;
2407 VERIFIER_DEBUG ( printf ("branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
2409 if (target < 0 || target >= ctx->code_size) {
2410 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
2414 switch (is_valid_cmp_branch_instruction (ctx->header, ctx->ip_offset, target)) {
2416 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2419 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2423 ctx->target = target;
2425 if (!check_underflow (ctx, 2))
2428 b = stack_pop (ctx);
2429 a = stack_pop (ctx);
2432 if (IS_MANAGED_POINTER (idxa))
2436 if (IS_MANAGED_POINTER (idxb))
2441 res = table [idxa][idxb];
2443 VERIFIER_DEBUG ( printf ("branch res %d\n", res); );
2444 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
2446 if (res == TYPE_INV) {
2447 ADD_VERIFY_ERROR (ctx,
2448 g_strdup_printf ("Compare and Branch instruction applyed to ill formed stack (%s x %s) at 0x%04x",
2449 type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)], ctx->ip_offset));
2450 } else if (res & NON_VERIFIABLE_RESULT) {
2451 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Compare and Branch instruction is not verifiable (%s x %s) at 0x%04x",
2452 type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)], ctx->ip_offset));
2453 res = res & ~NON_VERIFIABLE_RESULT;
2458 do_cmp_op (VerifyContext *ctx, const unsigned char table [TYPE_MAX][TYPE_MAX])
2464 if (!check_underflow (ctx, 2))
2466 b = stack_pop (ctx);
2467 a = stack_pop (ctx);
2470 if (IS_MANAGED_POINTER (idxa))
2474 if (IS_MANAGED_POINTER (idxb))
2479 res = table [idxa][idxb];
2481 if(res == TYPE_INV) {
2482 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf("Compare instruction applyed to ill formed stack (%s x %s) at 0x%04x", type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)], ctx->ip_offset));
2483 } else if (res & NON_VERIFIABLE_RESULT) {
2484 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Compare instruction is not verifiable (%s x %s) at 0x%04x",
2485 type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)], ctx->ip_offset));
2486 res = res & ~NON_VERIFIABLE_RESULT;
2488 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
2492 do_ret (VerifyContext *ctx)
2494 VERIFIER_DEBUG ( printf ("checking ret\n"); );
2495 if (ctx->signature->ret->type != MONO_TYPE_VOID) {
2497 if (!check_underflow (ctx, 1))
2500 top = stack_pop(ctx);
2502 if (!verify_stack_type_compatibility (ctx, ctx->signature->ret, top)) {
2503 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible return value on stack with method signature ret at 0x%04x", ctx->ip_offset));
2508 if (ctx->eval.size > 0) {
2509 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack not empty (%d) after ret at 0x%04x", ctx->eval.size, ctx->ip_offset));
2511 if (in_any_block (ctx->header, ctx->ip_offset))
2512 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ret cannot escape exception blocks at 0x%04x", ctx->ip_offset));
2515 /* FIXME: we could just load the signature instead of the whole MonoMethod
2516 * TODO handle vararg calls
2517 * TODO handle non virt calls to non-final virtual calls (from the verifiability clause in page 52 of partition 3)
2518 * TODO handle abstract calls
2519 * TODO handle calling .ctor outside one or calling the .ctor for other class but super
2520 * TODO handle call invoking virtual methods (only allowed to invoke super)
2523 do_invoke_method (VerifyContext *ctx, int method_token)
2526 MonoMethodSignature *sig;
2528 MonoMethod *method = mono_get_method_full (ctx->image, method_token, NULL, ctx->generic_context);
2531 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method 0x%08x not found at 0x%04x", method_token, ctx->ip_offset));
2535 if (!(sig = mono_method_signature (method)))
2536 sig = mono_method_get_signature (method, ctx->image, method_token);
2538 param_count = sig->param_count + sig->hasthis;
2539 if (!check_underflow (ctx, param_count))
2542 for (i = sig->param_count - 1; i >= 0; --i) {
2543 VERIFIER_DEBUG ( printf ("verifying argument %d\n", i); );
2544 value = stack_pop (ctx);
2545 if (!verify_stack_type_compatibility (ctx, sig->params[i], value))
2546 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible parameter value with function signature at 0x%04x", ctx->ip_offset));
2550 MonoType * type = method->klass->valuetype ? &method->klass->this_arg : &method->klass->byval_arg;
2552 VERIFIER_DEBUG ( printf ("verifying this argument\n"); );
2553 value = stack_pop (ctx);
2554 if (!verify_stack_type_compatibility (ctx, type, value)) {
2555 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Incompatible this argument on stack with method signature ret at 0x%04x", ctx->ip_offset));
2559 if (!mono_method_can_access_method (ctx->method, method))
2560 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method is not accessible at 0x%04x", ctx->ip_offset));
2562 if (sig->ret->type != MONO_TYPE_VOID) {
2563 if (check_overflow (ctx))
2564 set_stack_value (stack_push (ctx), sig->ret, FALSE);
2567 if (sig->ret->type == MONO_TYPE_TYPEDBYREF
2569 || (sig->ret->type == MONO_TYPE_VALUETYPE && !strcmp ("System", sig->ret->data.klass->name_space) && !strcmp ("ArgIterator", sig->ret->data.klass->name)))
2570 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method returns typedbyref, byref or ArgIterator at 0x%04x", ctx->ip_offset));
2574 do_push_static_field (VerifyContext *ctx, int token, gboolean take_addr)
2576 MonoClassField *field;
2579 field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context);
2581 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ctx->ip_offset));
2585 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
2586 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load non static field at 0x%04x", ctx->ip_offset));
2589 /*taking the address of initonly field only works from the static constructor */
2590 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
2591 !(field->parent == ctx->method->klass && (ctx->method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_STATIC)) && !strcmp (".cctor", ctx->method->name)))
2592 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
2594 if (!mono_method_can_access_field (ctx->method, field))
2595 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset));
2597 set_stack_value (stack_push (ctx), field->type, take_addr);
2601 do_store_static_field (VerifyContext *ctx, int token) {
2602 MonoClassField *field;
2606 if (!check_underflow (ctx, 1))
2609 value = stack_pop (ctx);
2611 field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context);
2613 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store field from token 0x%08x at 0x%04x", token, ctx->ip_offset));
2617 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
2618 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store non static field at 0x%04x", ctx->ip_offset));
2622 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
2623 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type in store static field at 0x%04x", ctx->ip_offset));
2627 if (!mono_method_can_access_field (ctx->method, field))
2628 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset));
2630 if (!verify_stack_type_compatibility (ctx, field->type, value))
2631 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in static field store at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
2635 check_is_valid_type_for_field_ops (VerifyContext *ctx, int token, ILStackDesc *obj, MonoClassField **ret_field)
2637 MonoClassField *field;
2640 /*must be one of: object type, managed pointer, unmanaged pointer (native int) or an instance of a value type */
2641 if (!((obj->stype == TYPE_COMPLEX)
2642 /* the managed reference must be to an object or value type */
2643 || (( IS_MANAGED_POINTER (obj->stype)) && (UNMASK_TYPE (obj->stype) == TYPE_COMPLEX))
2644 || (obj->stype == TYPE_NATIVE_INT)
2645 || (obj->stype == TYPE_PTR)
2646 || (obj->stype == TYPE_COMPLEX))) {
2647 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument %s to load field at 0x%04x", type_names [UNMASK_TYPE (obj->stype)], ctx->ip_offset));
2650 field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context);
2652 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ctx->ip_offset));
2658 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
2659 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type at 0x%04x", ctx->ip_offset));
2662 g_assert (obj->type);
2664 /*The value on the stack must be a subclass of the defining type of the field*/
2665 /* we need to check if we can load the field from the stack value*/
2666 if (UNMASK_TYPE (obj->stype) == TYPE_COMPLEX) {
2667 MonoType *type = obj->type->byref ? &field->parent->this_arg : &field->parent->byval_arg;
2669 if (!verify_type_compatibility (ctx, type, obj->type)) {
2670 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not compatible to reference the field at 0x%04x", ctx->ip_offset));
2673 if (!mono_method_can_access_field (ctx->method, field))
2674 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset));
2677 if (!mono_method_can_access_field (ctx->method, field))
2678 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset));
2680 if (obj->stype == TYPE_NATIVE_INT)
2681 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Native int is not a verifiable type to reference a field at 0x%04x", ctx->ip_offset));
2683 check_unmanaged_pointer (ctx, obj);
2688 do_push_field (VerifyContext *ctx, int token, gboolean take_addr)
2691 MonoClassField *field;
2693 if (!check_underflow (ctx, 1))
2695 obj = stack_pop (ctx);
2697 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field))
2700 if (take_addr && field->parent->valuetype && !IS_MANAGED_POINTER (obj->stype))
2701 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a temporary value-type at 0x%04x", ctx->ip_offset));
2703 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
2704 !(field->parent == ctx->method->klass && (ctx->method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && !strcmp (".ctor", ctx->method->name)))
2705 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
2707 set_stack_value (stack_push (ctx), field->type, take_addr);
2711 do_store_field (VerifyContext *ctx, int token)
2713 ILStackDesc *value, *obj;
2714 MonoClassField *field;
2716 if (!check_underflow (ctx, 2))
2719 value = stack_pop (ctx);
2720 obj = stack_pop (ctx);
2722 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field))
2725 if (!verify_stack_type_compatibility (ctx, field->type, value))
2726 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in field store at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
2729 /*TODO proper handle for Nullable<T>*/
2731 do_box_value (VerifyContext *ctx, int klass_token)
2734 MonoType *type = get_boxable_mono_type (ctx, klass_token);
2739 if (!check_underflow (ctx, 1))
2742 value = stack_top (ctx);
2743 /*box is a nop for reference types*/
2744 if (value->stype == TYPE_COMPLEX && MONO_TYPE_IS_REFERENCE (value->type) && MONO_TYPE_IS_REFERENCE (type))
2747 value = stack_pop (ctx);
2749 if (!verify_stack_type_compatibility (ctx, type, value))
2750 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for boxing operation at 0x%04x", ctx->ip_offset));
2752 stack_push_val (ctx, TYPE_COMPLEX, mono_class_get_type (mono_defaults.object_class));
2756 do_unbox_value (VerifyContext *ctx, int klass_token)
2759 MonoType *type = get_boxable_mono_type (ctx, klass_token);
2764 if (!check_underflow (ctx, 1))
2767 value = stack_pop (ctx);
2769 if (value->stype != TYPE_COMPLEX || value->type->type != MONO_TYPE_OBJECT)
2770 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type %s at stack for unbox operation at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
2772 //TODO Pushed managed pointer is haver controled mutability (CMMP)
2773 set_stack_value (stack_push (ctx), mono_type_get_type_byref (type), FALSE);
2777 do_unary_math_op (VerifyContext *ctx, int op)
2780 if (!check_underflow (ctx, 1))
2782 value = stack_top (ctx);
2783 switch(value->stype) {
2786 case TYPE_NATIVE_INT:
2791 case TYPE_COMPLEX: /*only enums are ok*/
2792 if (value->type->type == MONO_TYPE_VALUETYPE && value->type->data.klass->enumtype)
2795 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for unary not at 0x%04x", ctx->ip_offset));
2800 do_conversion (VerifyContext *ctx, int kind)
2803 if (!check_underflow (ctx, 1))
2805 value = stack_pop (ctx);
2807 switch(value->stype) {
2810 case TYPE_NATIVE_INT:
2814 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for conversion operation at 0x%04x", ctx->ip_offset));
2819 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
2822 stack_push_val (ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
2825 stack_push_val (ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
2827 case TYPE_NATIVE_INT:
2828 stack_push_val (ctx, TYPE_NATIVE_INT, &mono_defaults.int_class->byval_arg);
2831 g_error ("unknown type %02x in conversion", kind);
2837 do_load_token (VerifyContext *ctx, int token)
2840 MonoClass *handle_class;
2841 if (!check_overflow (ctx))
2843 handle = mono_ldtoken (ctx->image, token, &handle_class, ctx->generic_context);
2845 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid token 0x%x for ldtoken at 0x%04x", token, ctx->ip_offset));
2848 stack_push_val (ctx, TYPE_COMPLEX, mono_class_get_type (handle_class));
2852 do_ldobj_value (VerifyContext *ctx, int token)
2855 MonoType *type = get_boxable_mono_type (ctx, token);
2860 if (!check_underflow (ctx, 1))
2863 value = stack_pop (ctx);
2864 if (!IS_MANAGED_POINTER (value->stype)
2865 && value->stype != TYPE_NATIVE_INT
2866 && !(value->stype == TYPE_PTR && value->type->type != MONO_TYPE_FNPTR)) {
2867 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid argument %s to ldobj at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
2871 if (value->stype == TYPE_NATIVE_INT)
2872 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Using native pointer to ldobj at 0x%04x", ctx->ip_offset));
2874 /*We have a byval on the stack, but the comparison must be strict. */
2875 if (!verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (value->type), TRUE))
2876 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldojb operation at 0x%04x", ctx->ip_offset));
2878 set_stack_value (stack_push (ctx), type, FALSE);
2881 #define CTOR_REQUIRED_FLAGS (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_PUBLIC)
2882 #define CTOR_INVALID_FLAGS (METHOD_ATTRIBUTE_STATIC)
2883 /* TODO implement delegate verification */
2885 do_newobj (VerifyContext *ctx, int token)
2889 MonoMethodSignature *sig;
2890 MonoMethod *method = mono_get_method_full (ctx->image, token, NULL, ctx->generic_context);
2892 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Constructor 0x%08x not found at 0x%04x", token, ctx->ip_offset));
2896 if ((method->flags & CTOR_REQUIRED_FLAGS) != CTOR_REQUIRED_FLAGS
2897 || (method->flags & CTOR_INVALID_FLAGS) != 0
2898 || strcmp (".ctor", method->name)) {
2899 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method from token 0x%08x not a constructor at 0x%04x", token, ctx->ip_offset));
2903 if (method->klass->flags & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE))
2904 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Trying to instantiate an abstract or interface type at 0x%04x", ctx->ip_offset));
2906 sig = mono_method_signature (method);
2907 if (!check_underflow (ctx, sig->param_count))
2910 for (i = sig->param_count - 1; i >= 0; --i) {
2911 VERIFIER_DEBUG ( printf ("verifying constructor argument %d\n", i); );
2912 value = stack_pop (ctx);
2913 if (!verify_stack_type_compatibility (ctx, sig->params [i], value))
2914 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible parameter value with function signature at 0x%04x", ctx->ip_offset));
2917 if (check_overflow (ctx))
2918 set_stack_value (stack_push (ctx), &method->klass->byval_arg, FALSE);
2922 do_cast (VerifyContext *ctx, int token) {
2926 if (!check_underflow (ctx, 1))
2929 type = mono_type_get_full (ctx->image, token, ctx->generic_context);
2932 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
2937 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid castclass type at 0x%04x", ctx->ip_offset));
2941 value = stack_top (ctx);
2943 if (IS_MANAGED_POINTER (value->stype))
2944 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for checkast at 0x%04x", ctx->ip_offset));
2945 else if (mono_class_from_mono_type (value->type)->valuetype)
2946 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Value cannot be a valuetype for checkast at 0x%04x", ctx->ip_offset));
2948 switch (value->type->type) {
2949 case MONO_TYPE_FNPTR:
2951 case MONO_TYPE_TYPEDBYREF:
2952 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for checkast at 0x%04x", ctx->ip_offset));
2955 set_stack_value (value, type, FALSE);
2959 mono_type_from_opcode (int opcode) {
2967 return &mono_defaults.sbyte_class->byval_arg;
2975 return &mono_defaults.int16_class->byval_arg;
2983 return &mono_defaults.int32_class->byval_arg;
2989 return &mono_defaults.int64_class->byval_arg;
2995 return &mono_defaults.single_class->byval_arg;
3001 return &mono_defaults.double_class->byval_arg;
3007 return &mono_defaults.int_class->byval_arg;
3011 case CEE_LDELEM_REF:
3012 case CEE_STELEM_REF:
3013 return &mono_defaults.object_class->byval_arg;
3016 g_error ("unknown opcode %02x in mono_type_from_opcode ", opcode);
3022 do_load_indirect (VerifyContext *ctx, int opcode)
3025 if (!check_underflow (ctx, 1))
3028 value = stack_pop (ctx);
3029 if (!IS_MANAGED_POINTER (value->stype)) {
3030 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Load indirect not using a manager pointer at 0x%04x", ctx->ip_offset));
3031 set_stack_value (stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
3035 if (opcode == CEE_LDIND_REF) {
3036 if (UNMASK_TYPE (value->stype) != TYPE_COMPLEX || mono_class_from_mono_type (value->type)->valuetype)
3037 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind_ref expected object byref operation at 0x%04x", ctx->ip_offset));
3038 set_stack_value (stack_push (ctx), mono_type_get_type_byval (value->type), FALSE);
3040 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (value->type), TRUE))
3041 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
3042 set_stack_value (stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
3047 do_store_indirect (VerifyContext *ctx, int opcode)
3049 ILStackDesc *addr, *val;
3050 if (!check_underflow (ctx, 2))
3053 val = stack_pop (ctx);
3054 addr = stack_pop (ctx);
3056 check_unmanaged_pointer (ctx, addr);
3058 if (!IS_MANAGED_POINTER (addr->stype) && addr->stype != TYPE_PTR) {
3059 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid non-pointer argument to stind at 0x%04x", ctx->ip_offset));
3063 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (addr->type), TRUE))
3064 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid addr type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
3066 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (val->type), FALSE))
3067 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid addr type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
3071 do_newarr (VerifyContext *ctx, int token)
3074 MonoType *type = get_boxable_mono_type (ctx, token);
3079 if (!check_underflow (ctx, 1))
3082 value = stack_pop (ctx);
3083 if (value->stype != TYPE_I4 && value->stype != TYPE_NATIVE_INT)
3084 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Array size type on stack (%s) is not a verifiable type at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
3086 set_stack_value (stack_push (ctx), mono_class_get_type (mono_array_class_get (mono_class_from_mono_type (type), 1)), FALSE);
3089 /*FIXME handle arrays that are not 0-indexed*/
3091 do_ldlen (VerifyContext *ctx)
3095 if (!check_underflow (ctx, 1))
3098 value = stack_pop (ctx);
3100 if (value->stype != TYPE_COMPLEX || value->type->type != MONO_TYPE_SZARRAY)
3101 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type for ldlen at 0x%04x", ctx->ip_offset));
3103 stack_push_val (ctx, TYPE_NATIVE_INT, &mono_defaults.int_class->byval_arg);
3106 /*FIXME handle arrays that are not 0-indexed*/
3107 /*FIXME handle readonly prefix and CMMP*/
3109 do_ldelema (VerifyContext *ctx, int klass_token)
3111 ILStackDesc *index, *array;
3112 MonoType *type = get_boxable_mono_type (ctx, klass_token);
3118 if (!check_underflow (ctx, 2))
3121 index = stack_pop (ctx);
3122 array = stack_pop (ctx);
3124 if (index->stype != TYPE_I4 && index->stype != TYPE_NATIVE_INT)
3125 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Index type(%s) for ldelema is not an int or a native int at 0x%04x", type_names [UNMASK_TYPE (index->stype)], ctx->ip_offset));
3127 if (!IS_NULL_LITERAL (array->stype)) {
3128 if (array->stype != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
3129 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type(%s) for ldelema at 0x%04x", type_names [UNMASK_TYPE (array->stype)], ctx->ip_offset));
3131 if (get_stack_type (type) == TYPE_I4 || get_stack_type (type) == TYPE_NATIVE_INT)
3132 valid = verify_type_compatibility_full (ctx, type, &array->type->data.klass->byval_arg, TRUE);
3134 valid = mono_metadata_type_equal (type, &array->type->data.klass->byval_arg);
3136 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelema at 0x%04x", ctx->ip_offset));
3140 set_stack_value (stack_push (ctx), type, TRUE);
3143 /*FIXME handle arrays that are not 0-indexed*/
3144 /*FIXME handle readonly prefix and CMMP*/
3146 do_ldelem (VerifyContext *ctx, int opcode, int token)
3148 ILStackDesc *index, *array;
3150 if (!check_underflow (ctx, 2))
3153 if (opcode == CEE_LDELEM_ANY) {
3154 type = mono_type_get_full (ctx->image, token, ctx->generic_context);
3156 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
3160 type = mono_type_from_opcode (opcode);
3163 index = stack_pop (ctx);
3164 array = stack_pop (ctx);
3166 if (index->stype != TYPE_I4 && index->stype != TYPE_NATIVE_INT)
3167 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Index type(%s) for ldelema is not an int or a native int at 0x%04x", type_names [UNMASK_TYPE (index->stype)], ctx->ip_offset));
3169 if (!IS_NULL_LITERAL (array->stype)) {
3170 if (array->stype != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
3171 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type(%s) for ldelem.X at 0x%04x", type_names [UNMASK_TYPE (array->stype)], ctx->ip_offset));
3173 if (opcode == CEE_LDELEM_REF) {
3174 if (array->type->data.klass->valuetype)
3175 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for ldelem.ref 0x%04x", ctx->ip_offset));
3176 type = &array->type->data.klass->byval_arg;
3177 } else if (!verify_type_compatibility_full (ctx, type, &array->type->data.klass->byval_arg, TRUE)) {
3178 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
3183 set_stack_value (stack_push (ctx), type, FALSE);
3186 /*FIXME handle arrays that are not 0-indexed*/
3188 do_stelem (VerifyContext *ctx, int opcode, int token)
3190 ILStackDesc *index, *array, *value;
3192 if (!check_underflow (ctx, 3))
3195 if (opcode == CEE_STELEM_ANY) {
3196 type = mono_type_get_full (ctx->image, token, ctx->generic_context);
3198 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
3202 type = mono_type_from_opcode (opcode);
3205 value = stack_pop (ctx);
3206 index = stack_pop (ctx);
3207 array = stack_pop (ctx);
3209 if (index->stype != TYPE_I4 && index->stype != TYPE_NATIVE_INT)
3210 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Index type(%s) for stdelem.X is not an int or a native int at 0x%04x", type_names [UNMASK_TYPE (index->stype)], ctx->ip_offset));
3212 if (!IS_NULL_LITERAL (array->stype)) {
3213 if (array->stype != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY) {
3214 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type(%s) for stelem.X at 0x%04x", type_names [UNMASK_TYPE (array->stype)], ctx->ip_offset));
3216 if (opcode == CEE_STELEM_REF) {
3217 if (array->type->data.klass->valuetype)
3218 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
3219 } else if (!verify_type_compatibility_full (ctx, &array->type->data.klass->byval_arg, type, TRUE)) {
3220 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for stdelem.X at 0x%04x", ctx->ip_offset));
3225 if (opcode == CEE_STELEM_REF) {
3226 if (mono_class_from_mono_type(value->type)->valuetype)
3227 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
3228 } else if (opcode != CEE_STELEM_REF && !verify_type_compatibility_full (ctx, type, mono_type_from_stack_slot (value), FALSE)) {
3229 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value on stack for stdelem.X at 0x%04x", ctx->ip_offset));
3234 do_throw (VerifyContext *ctx)
3236 ILStackDesc *exception;
3237 if (!check_underflow (ctx, 1))
3239 exception = stack_pop (ctx);
3241 if (!IS_NULL_LITERAL (exception->stype) && !(exception->stype == TYPE_COMPLEX && !mono_class_from_mono_type (exception->type)->valuetype))
3242 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type on stack for throw, expected reference type at 0x%04x", ctx->ip_offset));
3244 /*The stack is left empty after a throw*/
3250 do_endfilter (VerifyContext *ctx)
3252 MonoExceptionClause *clause;
3254 if (IS_STRICT_MODE (ctx)) {
3255 if (ctx->eval.size != 1)
3256 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack size must have one item for endfilter at 0x%04x", ctx->ip_offset));
3258 if (ctx->eval.size >= 1 && stack_pop (ctx)->stype != TYPE_I4)
3259 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack item type is not an int32 for endfilter at 0x%04x", ctx->ip_offset));
3262 if ((clause = is_correct_endfilter (ctx, ctx->ip_offset))) {
3263 if (IS_STRICT_MODE (ctx)) {
3264 if (ctx->ip_offset != clause->handler_offset - 2)
3265 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
3267 if ((ctx->ip_offset != clause->handler_offset - 2) && !MONO_OFFSET_IN_HANDLER (clause, ctx->ip_offset))
3268 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
3271 if (IS_STRICT_MODE (ctx) && !is_unverifiable_endfilter (ctx, ctx->ip_offset))
3272 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
3274 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
3281 do_leave (VerifyContext *ctx, int delta)
3283 int target = ((gint32)ctx->ip_offset) + delta;
3284 if (target >= ctx->code_size || target < 0)
3285 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
3287 if (!is_correct_leave (ctx->header, ctx->ip_offset, target))
3288 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ctx->ip_offset));
3294 * Verify br and br.s opcodes.
3297 do_static_branch (VerifyContext *ctx, int delta)
3299 int target = ctx->ip_offset + delta;
3300 if (target < 0 || target >= ctx->code_size) {
3301 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("branch target out of code at 0x%04x", ctx->ip_offset));
3305 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
3307 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3310 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3314 ctx->target = target;
3318 do_switch (VerifyContext *ctx, int count, const unsigned char *data)
3320 int i, base = ctx->ip_offset + 5 + count * 4;
3323 if (!check_underflow (ctx, 1))
3326 value = stack_pop (ctx);
3328 if (value->stype != TYPE_I4 && value->stype != TYPE_NATIVE_INT)
3329 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to switch at 0x%04x", ctx->ip_offset));
3331 for (i = 0; i < count; ++i) {
3332 int target = base + read32 (data + i * 4);
3334 if (target < 0 || target >= ctx->code_size)
3335 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x out of code at 0x%04x", i, ctx->ip_offset));
3337 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
3339 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
3342 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
3345 merge_stacks (ctx, &ctx->eval, &ctx->code [target], FALSE, TRUE);
3349 /*Merge the stacks and perform compat checks*/
3351 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, int start, gboolean external)
3354 stack_init (ctx, to);
3357 if (to->flags == IL_CODE_FLAG_NOT_PROCESSED)
3360 stack_copy (&ctx->eval, to);
3362 } else if (!(to->flags & IL_CODE_STACK_MERGED)) {
3363 stack_copy (to, &ctx->eval);
3366 VERIFIER_DEBUG ( printf ("performing stack merge %d x %d\n", from->size, to->size); );
3368 if (from->size != to->size) {
3369 VERIFIER_DEBUG ( printf ("different stack sizes %d x %d at 0x%04x\n", from->size, to->size, ctx->ip_offset); );
3370 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));
3374 for (i = 0; i < from->size; ++i) {
3375 ILStackDesc *from_slot = from->stack + i;
3376 ILStackDesc *to_slot = to->stack + i;
3378 if (!verify_type_compatibility (ctx, mono_type_from_stack_slot (to_slot), mono_type_from_stack_slot (from_slot))) {
3379 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Could not merge stacks, types not compatible at 0x%04x", ctx->ip_offset));
3383 /*TODO we need to choose the base class for merging reference types*/
3384 copy_stack_value (to_slot, from_slot);
3389 to->flags |= IL_CODE_FLAG_WAS_TARGET;
3390 to->flags |= IL_CODE_STACK_MERGED;
3393 #define HANDLER_START(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER ? (clause)->data.filter_offset : clause->handler_offset)
3394 #define IS_CATCH_OR_FILTER(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER || (clause)->flags == MONO_EXCEPTION_CLAUSE_NONE)
3397 * is_clause_in_range :
3399 * Returns TRUE if either the protected block or the handler of @clause is in the @start - @end range.
3402 is_clause_in_range (MonoExceptionClause *clause, guint32 start, guint32 end)
3404 if (clause->try_offset >= start && clause->try_offset < end)
3406 if (HANDLER_START (clause) >= start && HANDLER_START (clause) < end)
3412 * is_clause_inside_range :
3414 * Returns TRUE if @clause lies completely inside the @start - @end range.
3417 is_clause_inside_range (MonoExceptionClause *clause, guint32 start, guint32 end)
3419 if (clause->try_offset < start || (clause->try_offset + clause->try_len) > end)
3421 if (HANDLER_START (clause) < start || (clause->handler_offset + clause->handler_len) > end)
3427 * is_clause_nested :
3429 * Returns TRUE if @nested is nested in @clause.
3432 is_clause_nested (MonoExceptionClause *clause, MonoExceptionClause *nested)
3434 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (nested, clause->data.filter_offset, clause->handler_offset))
3436 return is_clause_inside_range (nested, clause->try_offset, clause->try_offset + clause->try_len) ||
3437 is_clause_inside_range (nested, clause->handler_offset, clause->handler_offset + clause->handler_len);
3440 /* Test the relationship between 2 exception clauses. Follow P.1 12.4.2.7 of ECMA
3441 * the each pair of exception must have the following properties:
3442 * - one is fully nested on another (the outer must not be a filter clause) (the nested one must come earlier)
3443 * - completely disjoin (none of the 3 regions of each entry overlap with the other 3)
3444 * - mutual protection (protected block is EXACT the same, handlers are disjoin and all handler are catch or all handler are filter)
3447 verify_clause_relationship (VerifyContext *ctx, MonoExceptionClause *clause, MonoExceptionClause *to_test)
3449 /*clause is nested*/
3450 if (is_clause_nested (to_test, clause)) {
3451 if (to_test->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3452 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clause inside filter"));
3457 /*wrong nesting order.*/
3458 if (is_clause_nested (clause, to_test)) {
3459 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Nested exception clause appears after enclosing clause"));
3463 /*mutual protection*/
3464 if (clause->try_offset == to_test->try_offset && clause->try_len == to_test->try_len) {
3465 /*handlers are not disjoint*/
3466 if (is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) {
3467 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception handlers overlap"));
3470 /* handlers are not catch or filter */
3471 if (!IS_CATCH_OR_FILTER (clause) || !IS_CATCH_OR_FILTER (to_test)) {
3472 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses with shared protected block are neither catch or filter"));
3479 /*not completelly disjoint*/
3480 if (is_clause_in_range (to_test, clause->try_offset, clause->try_offset + clause->try_len) ||
3481 is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len))
3482 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses overlap"));
3486 * FIXME: need to distinguish between valid and verifiable.
3487 * Need to keep track of types on the stack.
3488 * Verify types for opcodes.
3491 mono_method_verify (MonoMethod *method, int level)
3493 const unsigned char *ip;
3494 const unsigned char *end;
3495 int i, n, need_merge = 0, start = 0;
3496 guint token, ip_offset = 0, prefix = 0, prefix_list = 0;
3497 MonoGenericContext *generic_context = NULL;
3500 VERIFIER_DEBUG ( printf ("Verify IL for method %s %s %s\n", method->klass->name, method->klass->name, method->name); );
3502 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
3503 (method->flags & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT))) {
3507 memset (&ctx, 0, sizeof (VerifyContext));
3509 ctx.signature = mono_method_signature (method);
3510 if (!ctx.signature) {
3511 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method signature"));
3514 ctx.header = mono_method_get_header (method);
3516 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method header"));
3519 ctx.method = method;
3520 ip = ctx.header->code;
3521 end = ip + ctx.header->code_size;
3522 ctx.image = image = method->klass->image;
3525 ctx.max_args = ctx.signature->param_count + ctx.signature->hasthis;
3526 ctx.max_stack = ctx.header->max_stack;
3527 ctx.verifiable = ctx.valid = 1;
3530 ctx.code = g_new0 (ILCodeDesc, ctx.header->code_size);
3531 ctx.code_size = ctx.header->code_size;
3533 memset(ctx.code, 0, sizeof (ILCodeDesc) * ctx.header->code_size);
3536 ctx.num_locals = ctx.header->num_locals;
3537 ctx.locals = ctx.header->locals;
3540 if (ctx.signature->hasthis) {
3541 ctx.params = g_new0 (MonoType*, ctx.max_args);
3542 ctx.params [0] = method->klass->valuetype ? &method->klass->this_arg : &method->klass->byval_arg;
3543 memcpy (ctx.params + 1, ctx.signature->params, sizeof (MonoType *) * ctx.signature->param_count);
3545 ctx.params = ctx.signature->params;
3548 if (ctx.signature->is_inflated)
3549 ctx.generic_context = generic_context = mono_method_get_context (method);
3551 stack_init (&ctx, &ctx.eval);
3553 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
3554 MonoExceptionClause *clause = ctx.header->clauses + i;
3555 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); );
3557 if (clause->try_offset > ctx.code_size)
3558 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause out of bounds at 0x%04x", clause->try_offset));
3560 if (clause->try_len <= 0)
3561 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause len <= 0 at 0x%04x", clause->try_offset));
3563 if (clause->handler_offset > ctx.code_size)
3564 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause out of bounds at 0x%04x", clause->try_offset));
3566 if (clause->handler_len <= 0)
3567 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause len <= 0 at 0x%04x", clause->try_offset));
3569 if (clause->try_offset < clause->handler_offset && clause->try_offset + clause->try_len > HANDLER_START (clause))
3570 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try block (at 0x%04x) includes handler block (at 0x%04x)", clause->try_offset, clause->handler_offset));
3572 for (n = i + 1; n < ctx.header->num_clauses && ctx.valid; ++n)
3573 verify_clause_relationship (&ctx, clause, ctx.header->clauses + n);
3578 ctx.code [clause->try_offset].flags |= IL_CODE_FLAG_WAS_TARGET;
3579 ctx.code [clause->try_offset + clause->try_len].flags |= IL_CODE_FLAG_WAS_TARGET;
3580 ctx.code [clause->handler_offset + clause->handler_len].flags |= IL_CODE_FLAG_WAS_TARGET;
3582 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
3583 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, clause->data.catch_class);
3585 else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3586 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->data.filter_offset, mono_defaults.exception_class);
3587 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, mono_defaults.exception_class);
3591 while (ip < end && ctx.valid) {
3592 ctx.ip_offset = ip_offset = ip - ctx.header->code;
3594 /*We need to check against fallthrou in and out of protected blocks.
3595 * For fallout we check the once a protected block ends, if the start flag is not set.
3596 * Likewise for fallthru in, we check if ip is the start of a protected block and start is not set
3597 * TODO convert these checks to be done using flags and not this loop
3599 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
3600 MonoExceptionClause *clause = ctx.header->clauses + i;
3602 if ((clause->try_offset + clause->try_len == ip_offset) && start == 0) {
3603 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru off try block at 0x%04x", ip_offset));
3607 if ((clause->handler_offset + clause->handler_len == ip_offset) && start == 0) {
3608 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
3609 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
3611 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
3615 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && clause->handler_offset == ip_offset && start == 0) {
3616 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of filter block at 0x%04x", ip_offset));
3620 if (clause->handler_offset == ip_offset && start == 0) {
3621 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru handler block at 0x%04x", ip_offset));
3625 if (clause->try_offset == ip_offset && ctx.eval.size > 0) {
3626 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Try to enter try block with a non-empty stack at 0x%04x", ip_offset));
3634 /*TODO id stack merge fails, we break, should't we - or only on errors??
3635 TODO verify need_merge
3638 VERIFIER_DEBUG ( printf ("extra merge needed! 0x%04x \n", ctx.target); );
3639 merge_stacks (&ctx, &ctx.eval, &ctx.code [ctx.target], FALSE, TRUE);
3642 merge_stacks (&ctx, &ctx.eval, &ctx.code[ip_offset], start, FALSE);
3645 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
3647 prefix_list |= prefix;
3650 ctx.code [ip_offset].flags |= IL_CODE_FLAG_SEEN;
3654 #ifdef MONO_VERIFIER_DEBUG
3657 discode = mono_disasm_code_one (NULL, method, ip, NULL);
3658 discode [strlen (discode) - 1] = 0; /* no \n */
3659 g_print ("[%d] %-29s (%d)\n", ip_offset, discode, ctx.eval.size);
3662 dump_stack_state (&ctx.code [ip_offset]);
3663 dump_stack_state (&ctx.eval);
3676 push_arg (&ctx, *ip - CEE_LDARG_0, FALSE);
3682 push_arg (&ctx, ip [1], *ip == CEE_LDARGA_S);
3687 do_binop (&ctx, *ip, add_table);
3692 do_binop (&ctx, *ip, sub_table);
3699 do_binop (&ctx, *ip, bin_op_table);
3708 do_binop (&ctx, *ip, int_bin_op_table);
3715 do_binop (&ctx, *ip, shift_op_table);
3720 if (!check_underflow (&ctx, 1))
3736 /*TODO support definite assignment verification? */
3737 push_local (&ctx, *ip - CEE_LDLOC_0, FALSE);
3745 store_local (&ctx, *ip - CEE_STLOC_0);
3750 store_local (&ctx, ip [1]);
3755 store_arg (&ctx, ip [1]);
3769 if (check_overflow (&ctx))
3770 stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3775 if (check_overflow (&ctx))
3776 stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3781 if (check_overflow (&ctx))
3782 stack_push_val (&ctx,TYPE_I4, &mono_defaults.int32_class->byval_arg);
3787 if (check_overflow (&ctx))
3788 stack_push_val (&ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
3793 if (check_overflow (&ctx))
3794 stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
3799 if (check_overflow (&ctx))
3800 stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
3805 if (check_overflow (&ctx))
3806 stack_push_val (&ctx, TYPE_COMPLEX | NULL_LITERAL_MASK, &mono_defaults.object_class->byval_arg);
3812 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_eq_op);
3825 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_op);
3832 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_eq_op);
3845 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_op);
3852 push_local (&ctx, ip[1], *ip == CEE_LDLOCA_S);
3856 /* FIXME: warn/error instead? */
3863 if (!check_underflow (&ctx, 1))
3865 if (!check_overflow (&ctx))
3867 top = stack_push (&ctx);
3868 copy_stack_value (top, stack_get (&ctx, 1));
3875 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Eval stack must be empty in jmp at 0x%04x", ip_offset));
3876 token = read32 (ip + 1);
3877 if (in_any_block (ctx.header, ip_offset))
3878 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("jmp cannot escape exception blocks at 0x%04x", ip_offset));
3880 * FIXME: check signature, retval, arguments etc.
3886 do_invoke_method (&ctx, read32 (ip + 1));
3891 token = read32 (ip + 1);
3893 * FIXME: check signature, retval, arguments etc.
3898 do_static_branch (&ctx, (signed char)ip [1] + 2);
3906 do_boolean_branch_op (&ctx, (signed char)ip [1] + 2);
3912 do_static_branch (&ctx, (gint32)read32 (ip + 1) + 5);
3920 do_boolean_branch_op (&ctx, (gint32)read32 (ip + 1) + 5);
3926 n = read32 (ip + 1);
3927 do_switch (&ctx, n, (ip + 5));
3929 ip += 5 + sizeof (guint32) * n;
3943 do_load_indirect (&ctx, *ip);
3955 do_store_indirect (&ctx, *ip);
3961 do_unary_math_op (&ctx, *ip);
3965 //TODO: implement proper typecheck
3972 do_conversion (&ctx, TYPE_I4);
3978 do_conversion (&ctx, TYPE_I8);
3985 do_conversion (&ctx, TYPE_R8);
3991 do_conversion (&ctx, TYPE_NATIVE_INT);
3996 token = read32 (ip + 1);
3997 if (!check_underflow (&ctx, 2))
4004 do_ldobj_value (&ctx, read32 (ip + 1));
4009 /*TODO verify if token is a valid string literal*/
4010 token = read32 (ip + 1);
4011 if (check_overflow (&ctx))
4012 stack_push_val (&ctx, TYPE_COMPLEX, &mono_defaults.string_class->byval_arg);
4017 do_newobj (&ctx, read32 (ip + 1));
4023 do_cast (&ctx, read32 (ip + 1));
4029 ++ip; /* warn, error ? */
4032 do_unbox_value (&ctx, read32 (ip + 1));
4044 do_push_field (&ctx, read32 (ip + 1), *ip == CEE_LDFLDA);
4050 do_push_static_field (&ctx, read32 (ip + 1), *ip == CEE_LDSFLDA);
4055 do_store_field (&ctx, read32 (ip + 1));
4060 do_store_static_field (&ctx, read32 (ip + 1));
4064 if (!check_underflow (&ctx, 2))
4067 token = read32 (ip + 1);
4071 case CEE_CONV_OVF_I1_UN:
4072 case CEE_CONV_OVF_I2_UN:
4073 case CEE_CONV_OVF_I4_UN:
4074 case CEE_CONV_OVF_U1_UN:
4075 case CEE_CONV_OVF_U2_UN:
4076 case CEE_CONV_OVF_U4_UN:
4077 do_conversion (&ctx, TYPE_I4);
4081 case CEE_CONV_OVF_I8_UN:
4082 case CEE_CONV_OVF_U8_UN:
4083 do_conversion (&ctx, TYPE_I8);
4087 case CEE_CONV_OVF_I_UN:
4088 case CEE_CONV_OVF_U_UN:
4089 do_conversion (&ctx, TYPE_NATIVE_INT);
4094 do_box_value (&ctx, read32 (ip + 1));
4099 do_newarr (&ctx, read32 (ip + 1));
4109 do_ldelema (&ctx, read32 (ip + 1));
4123 case CEE_LDELEM_REF:
4124 do_ldelem (&ctx, *ip, 0);
4135 case CEE_STELEM_REF:
4136 do_stelem (&ctx, *ip, 0);
4140 case CEE_LDELEM_ANY:
4141 do_ldelem (&ctx, *ip, read32 (ip + 1));
4145 case CEE_STELEM_ANY:
4146 do_stelem (&ctx, *ip, read32 (ip + 1));
4164 ++ip; /* warn, error ? */
4167 case CEE_CONV_OVF_I1:
4168 case CEE_CONV_OVF_U1:
4169 case CEE_CONV_OVF_I2:
4170 case CEE_CONV_OVF_U2:
4171 case CEE_CONV_OVF_I4:
4172 case CEE_CONV_OVF_U4:
4173 do_conversion (&ctx, TYPE_I4);
4177 case CEE_CONV_OVF_I8:
4178 case CEE_CONV_OVF_U8:
4179 do_conversion (&ctx, TYPE_I8);
4183 case CEE_CONV_OVF_I:
4184 case CEE_CONV_OVF_U:
4185 do_conversion (&ctx, TYPE_NATIVE_INT);
4196 ++ip; /* warn, error ? */
4199 if (!check_underflow (&ctx, 1))
4204 if (!check_underflow (&ctx, 1))
4210 ++ip; /* warn, error ? */
4213 if (!check_underflow (&ctx, 1))
4215 token = read32 (ip + 1);
4227 ++ip; /* warn, error ? */
4230 do_load_token (&ctx, read32 (ip + 1));
4235 case CEE_ADD_OVF_UN:
4237 case CEE_MUL_OVF_UN:
4239 case CEE_SUB_OVF_UN:
4240 if (!check_underflow (&ctx, 2))
4245 case CEE_ENDFINALLY:
4246 if (!is_correct_endfinally (ctx.header, ip_offset))
4247 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("endfinally must be used inside a finally/fault handler at 0x%04x", ctx.ip_offset));
4254 do_leave (&ctx, read32 (ip + 1) + 5);
4260 do_leave (&ctx, (signed char)ip [1] + 2);
4303 store_local (&ctx, read16 (ip + 1));
4308 do_cmp_op (&ctx, cmp_br_eq_op);
4316 do_cmp_op (&ctx, cmp_br_op);
4321 store_arg (&ctx, read16 (ip + 1) );
4327 check_overflow (&ctx);
4330 if (!check_overflow (&ctx))
4332 token = read32 (ip + 1);
4334 stack_top (&ctx)->stype = TYPE_PTR;
4338 if (!check_underflow (&ctx, 1))
4340 token = read32 (ip + 1);
4342 if (stack_top (&ctx)->stype != TYPE_COMPLEX)
4343 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid argument to ldvirtftn at 0x%04x", ip_offset));
4344 stack_top (&ctx)->stype = TYPE_PTR;
4352 push_arg (&ctx, read16 (ip + 1), *ip == CEE_LDARGA);
4358 push_local (&ctx, read16 (ip + 1), *ip == CEE_LDLOCA);
4363 if (ctx.eval.size != 1)
4364 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ip_offset));
4365 if (stack_top (&ctx)->stype != TYPE_I4 && stack_top (&ctx)->stype != TYPE_PTR)
4366 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid argument to localloc at 0x%04x", ip_offset));
4367 stack_top (&ctx)->stype = TYPE_COMPLEX;
4374 do_endfilter (&ctx);
4378 case CEE_UNALIGNED_:
4379 prefix |= PREFIX_UNALIGNED;
4383 prefix |= PREFIX_VOLATILE;
4387 prefix |= PREFIX_TAIL;
4389 if (ip < end && (*ip != CEE_CALL && *ip != CEE_CALLI && *ip != CEE_CALLVIRT))
4390 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("tail prefix must be used only with call opcodes at 0x%04x", ip_offset));
4393 if (!check_underflow (&ctx, 1))
4395 token = read32 (ip + 1);
4399 case CEE_CONSTRAINED_:
4400 token = read32 (ip + 1);
4404 if (!check_underflow (&ctx, 3))
4409 if (!check_underflow (&ctx, 3))
4417 if (!is_correct_rethrow (ctx.header, ip_offset))
4418 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("rethrow must be used inside a catch handler at 0x%04x", ctx.ip_offset));
4426 if (!check_overflow (&ctx))
4428 token = read32 (ip + 1);
4430 stack_top (&ctx)->type = &mono_defaults.uint32_class->byval_arg;
4431 stack_top (&ctx)->stype = TYPE_I4;
4434 case CEE_REFANYTYPE:
4435 if (!check_underflow (&ctx, 1))
4449 * if ip != end we overflowed: mark as error.
4451 if ((ip != end || !start) && ctx.verifiable && !ctx.list) {
4452 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Run ahead of method code at 0x%04x", ip_offset));
4455 /*We should guard against the last decoded opcode, otherwise we might add errors that doesn't make sense.*/
4456 for (i = 0; i < ctx.code_size && i < ip_offset; ++i) {
4457 if ((ctx.code [i].flags & IL_CODE_FLAG_WAS_TARGET) && !(ctx.code [i].flags & IL_CODE_FLAG_SEEN))
4458 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or exception block target middle of intruction at 0x%04x", i));
4463 for (i = 0; i < ctx.header->code_size; ++i) {
4464 if (ctx.code [i].stack)
4465 g_free (ctx.code [i].stack);
4470 g_free (ctx.eval.stack);
4473 if (ctx.signature->hasthis)
4474 g_free (ctx.params);
4486 const FieldDesc *fields;
4489 static const FieldDesc
4490 typebuilder_fields[] = {
4491 {"tname", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, name)},
4492 {"nspace", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, nspace)},
4493 {"parent", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, parent)},
4494 {"interfaces", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, interfaces)},
4495 {"methods", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, methods)},
4496 {"properties", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, properties)},
4497 {"fields", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, fields)},
4498 {"attrs", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, attrs)},
4499 {"table_idx", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, table_idx)},
4503 static const FieldDesc
4504 modulebuilder_fields[] = {
4505 {"types", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, types)},
4506 {"cattrs", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, cattrs)},
4507 {"guid", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, guid)},
4508 {"table_idx", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, table_idx)},
4512 static const FieldDesc
4513 assemblybuilder_fields[] = {
4514 {"entry_point", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, entry_point)},
4515 {"modules", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, modules)},
4516 {"name", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, name)},
4517 {"resources", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, resources)},
4518 {"version", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, version)},
4519 {"culture", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, culture)},
4523 static const FieldDesc
4524 ctorbuilder_fields[] = {
4525 {"ilgen", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, ilgen)},
4526 {"parameters", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, parameters)},
4527 {"attrs", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, attrs)},
4528 {"iattrs", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, iattrs)},
4529 {"table_idx", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, table_idx)},
4530 {"call_conv", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, call_conv)},
4531 {"type", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, type)},
4535 static const FieldDesc
4536 methodbuilder_fields[] = {
4537 {"mhandle", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, mhandle)},
4538 {"rtype", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, rtype)},
4539 {"parameters", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, parameters)},
4540 {"attrs", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, attrs)},
4541 {"iattrs", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, iattrs)},
4542 {"name", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, name)},
4543 {"table_idx", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, table_idx)},
4544 {"code", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, code)},
4545 {"ilgen", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, ilgen)},
4546 {"type", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, type)},
4547 {"pinfo", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, pinfo)},
4548 {"pi_dll", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, dll)},
4549 {"pi_entry", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, dllentry)},
4550 {"charset", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, charset)},
4551 {"extra_flags", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, extra_flags)},
4552 {"native_cc", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, native_cc)},
4553 {"call_conv", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, call_conv)},
4557 static const FieldDesc
4558 fieldbuilder_fields[] = {
4559 {"attrs", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, attrs)},
4560 {"type", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, type)},
4561 {"name", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, name)},
4562 {"def_value", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, def_value)},
4563 {"offset", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, offset)},
4564 {"table_idx", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, table_idx)},
4568 static const FieldDesc
4569 propertybuilder_fields[] = {
4570 {"attrs", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, attrs)},
4571 {"name", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, name)},
4572 {"type", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, type)},
4573 {"parameters", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, parameters)},
4574 {"def_value", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, def_value)},
4575 {"set_method", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, set_method)},
4576 {"get_method", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, get_method)},
4577 {"table_idx", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, table_idx)},
4581 static const FieldDesc
4582 ilgenerator_fields[] = {
4583 {"code", G_STRUCT_OFFSET (MonoReflectionILGen, code)},
4584 {"code_len", G_STRUCT_OFFSET (MonoReflectionILGen, code_len)},
4585 {"max_stack", G_STRUCT_OFFSET (MonoReflectionILGen, max_stack)},
4586 {"cur_stack", G_STRUCT_OFFSET (MonoReflectionILGen, cur_stack)},
4587 {"locals", G_STRUCT_OFFSET (MonoReflectionILGen, locals)},
4588 {"ex_handlers", G_STRUCT_OFFSET (MonoReflectionILGen, ex_handlers)},
4592 static const FieldDesc
4593 ilexinfo_fields[] = {
4594 {"handlers", G_STRUCT_OFFSET (MonoILExceptionInfo, handlers)},
4595 {"start", G_STRUCT_OFFSET (MonoILExceptionInfo, start)},
4596 {"len", G_STRUCT_OFFSET (MonoILExceptionInfo, len)},
4597 {"end", G_STRUCT_OFFSET (MonoILExceptionInfo, label)},
4601 static const FieldDesc
4602 ilexblock_fields[] = {
4603 {"extype", G_STRUCT_OFFSET (MonoILExceptionBlock, extype)},
4604 {"type", G_STRUCT_OFFSET (MonoILExceptionBlock, type)},
4605 {"start", G_STRUCT_OFFSET (MonoILExceptionBlock, start)},
4606 {"len", G_STRUCT_OFFSET (MonoILExceptionBlock, len)},
4607 {"filter_offset", G_STRUCT_OFFSET (MonoILExceptionBlock, filter_offset)},
4611 static const ClassDesc
4612 emit_classes_to_check [] = {
4613 {"TypeBuilder", typebuilder_fields},
4614 {"ModuleBuilder", modulebuilder_fields},
4615 {"AssemblyBuilder", assemblybuilder_fields},
4616 {"ConstructorBuilder", ctorbuilder_fields},
4617 {"MethodBuilder", methodbuilder_fields},
4618 {"FieldBuilder", fieldbuilder_fields},
4619 {"PropertyBuilder", propertybuilder_fields},
4620 {"ILGenerator", ilgenerator_fields},
4621 {"ILExceptionBlock", ilexblock_fields},
4622 {"ILExceptionInfo", ilexinfo_fields},
4626 static const FieldDesc
4627 monoevent_fields[] = {
4628 {"klass", G_STRUCT_OFFSET (MonoReflectionEvent, klass)},
4629 {"handle", G_STRUCT_OFFSET (MonoReflectionEvent, event)},
4633 static const FieldDesc
4634 monoproperty_fields[] = {
4635 {"klass", G_STRUCT_OFFSET (MonoReflectionProperty, klass)},
4636 {"prop", G_STRUCT_OFFSET (MonoReflectionProperty, property)},
4640 static const FieldDesc
4641 monofield_fields[] = {
4642 {"klass", G_STRUCT_OFFSET (MonoReflectionField, klass)},
4643 {"fhandle", G_STRUCT_OFFSET (MonoReflectionField, field)},
4647 static const FieldDesc
4648 monomethodinfo_fields[] = {
4649 {"parent", G_STRUCT_OFFSET (MonoMethodInfo, parent)},
4650 {"ret", G_STRUCT_OFFSET (MonoMethodInfo, ret)},
4651 {"attrs", G_STRUCT_OFFSET (MonoMethodInfo, attrs)},
4652 {"iattrs", G_STRUCT_OFFSET (MonoMethodInfo, implattrs)},
4656 static const FieldDesc
4657 monopropertyinfo_fields[] = {
4658 {"parent", G_STRUCT_OFFSET (MonoPropertyInfo, parent)},
4659 {"name", G_STRUCT_OFFSET (MonoPropertyInfo, name)},
4660 {"get_method", G_STRUCT_OFFSET (MonoPropertyInfo, get)},
4661 {"set_method", G_STRUCT_OFFSET (MonoPropertyInfo, set)},
4662 {"attrs", G_STRUCT_OFFSET (MonoPropertyInfo, attrs)},
4666 static const FieldDesc
4667 monomethod_fields[] = {
4668 {"mhandle", G_STRUCT_OFFSET (MonoReflectionMethod, method)},
4672 static const FieldDesc
4673 monocmethod_fields[] = {
4674 {"mhandle", G_STRUCT_OFFSET (MonoReflectionMethod, method)},
4678 static const FieldDesc
4680 {"ClassImpl", G_STRUCT_OFFSET (MonoReflectionParameter, ClassImpl)},
4681 {"DefaultValueImpl", G_STRUCT_OFFSET (MonoReflectionParameter, DefaultValueImpl)},
4682 {"MemberImpl", G_STRUCT_OFFSET (MonoReflectionParameter, MemberImpl)},
4683 {"NameImpl", G_STRUCT_OFFSET (MonoReflectionParameter, NameImpl)},
4684 {"PositionImpl", G_STRUCT_OFFSET (MonoReflectionParameter, PositionImpl)},
4685 {"AttrsImpl", G_STRUCT_OFFSET (MonoReflectionParameter, AttrsImpl)},
4689 static const ClassDesc
4690 reflection_classes_to_check [] = {
4691 {"MonoEvent", monoevent_fields},
4692 {"MonoProperty", monoproperty_fields},
4693 {"MonoField", monofield_fields},
4694 {"MonoMethodInfo", monomethodinfo_fields},
4695 {"MonoPropertyInfo", monopropertyinfo_fields},
4696 {"MonoMethod", monomethod_fields},
4697 {"MonoCMethod", monocmethod_fields},
4698 {"ParameterInfo", pinfo_fields},
4703 enuminfo_fields[] = {
4704 {"utype", G_STRUCT_OFFSET (MonoEnumInfo, utype)},
4705 {"values", G_STRUCT_OFFSET (MonoEnumInfo, values)},
4706 {"names", G_STRUCT_OFFSET (MonoEnumInfo, names)},
4711 delegate_fields[] = {
4712 {"target_type", G_STRUCT_OFFSET (MonoDelegate, target_type)},
4713 {"m_target", G_STRUCT_OFFSET (MonoDelegate, target)},
4714 {"method_name", G_STRUCT_OFFSET (MonoDelegate, method_name)},
4715 {"method_ptr", G_STRUCT_OFFSET (MonoDelegate, method_ptr)},
4716 {"delegate_trampoline", G_STRUCT_OFFSET (MonoDelegate, delegate_trampoline)},
4717 {"method_info", G_STRUCT_OFFSET (MonoDelegate, method_info)},
4722 multicast_delegate_fields[] = {
4723 {"prev", G_STRUCT_OFFSET (MonoMulticastDelegate, prev)},
4728 async_result_fields[] = {
4729 {"async_state", G_STRUCT_OFFSET (MonoAsyncResult, async_state)},
4730 {"handle", G_STRUCT_OFFSET (MonoAsyncResult, handle)},
4731 {"async_delegate", G_STRUCT_OFFSET (MonoAsyncResult, async_delegate)},
4732 {"data", G_STRUCT_OFFSET (MonoAsyncResult, data)},
4733 {"sync_completed", G_STRUCT_OFFSET (MonoAsyncResult, sync_completed)},
4734 {"completed", G_STRUCT_OFFSET (MonoAsyncResult, completed)},
4735 {"endinvoke_called", G_STRUCT_OFFSET (MonoAsyncResult, endinvoke_called)},
4736 {"async_callback", G_STRUCT_OFFSET (MonoAsyncResult, async_callback)},
4741 exception_fields[] = {
4742 {"trace_ips", G_STRUCT_OFFSET (MonoException, trace_ips)},
4743 {"inner_exception", G_STRUCT_OFFSET (MonoException, inner_ex)},
4744 {"message", G_STRUCT_OFFSET (MonoException, message)},
4745 {"help_link", G_STRUCT_OFFSET (MonoException, help_link)},
4746 {"class_name", G_STRUCT_OFFSET (MonoException, class_name)},
4747 {"stack_trace", G_STRUCT_OFFSET (MonoException, stack_trace)},
4748 {"remote_stack_trace", G_STRUCT_OFFSET (MonoException, remote_stack_trace)},
4749 {"remote_stack_index", G_STRUCT_OFFSET (MonoException, remote_stack_index)},
4750 {"hresult", G_STRUCT_OFFSET (MonoException, hresult)},
4751 {"source", G_STRUCT_OFFSET (MonoException, source)},
4755 static const ClassDesc
4756 system_classes_to_check [] = {
4757 {"Exception", exception_fields},
4758 {"MonoEnumInfo", enuminfo_fields},
4759 {"Delegate", delegate_fields},
4760 {"MulticastDelegate", multicast_delegate_fields},
4765 stack_frame_fields [] = {
4766 {"ilOffset", G_STRUCT_OFFSET (MonoStackFrame, il_offset)},
4767 {"nativeOffset", G_STRUCT_OFFSET (MonoStackFrame, native_offset)},
4768 {"methodBase", G_STRUCT_OFFSET (MonoStackFrame, method)},
4769 {"fileName", G_STRUCT_OFFSET (MonoStackFrame, filename)},
4770 {"lineNumber", G_STRUCT_OFFSET (MonoStackFrame, line)},
4771 {"columnNumber", G_STRUCT_OFFSET (MonoStackFrame, column)},
4775 static const ClassDesc
4776 system_diagnostics_classes_to_check [] = {
4777 {"StackFrame", stack_frame_fields},
4782 mono_method_message_fields[] = {
4783 {"method", G_STRUCT_OFFSET (MonoMethodMessage, method)},
4784 {"args", G_STRUCT_OFFSET (MonoMethodMessage, args)},
4785 {"names", G_STRUCT_OFFSET (MonoMethodMessage, names)},
4786 {"arg_types", G_STRUCT_OFFSET (MonoMethodMessage, arg_types)},
4787 {"ctx", G_STRUCT_OFFSET (MonoMethodMessage, ctx)},
4788 {"rval", G_STRUCT_OFFSET (MonoMethodMessage, rval)},
4789 {"exc", G_STRUCT_OFFSET (MonoMethodMessage, exc)},
4793 static const ClassDesc
4794 messaging_classes_to_check [] = {
4795 {"AsyncResult", async_result_fields},
4796 {"MonoMethodMessage", mono_method_message_fields},
4801 transparent_proxy_fields[] = {
4802 {"_rp", G_STRUCT_OFFSET (MonoTransparentProxy, rp)},
4803 {"_class", G_STRUCT_OFFSET (MonoTransparentProxy, remote_class)},
4808 real_proxy_fields[] = {
4809 {"class_to_proxy", G_STRUCT_OFFSET (MonoRealProxy, class_to_proxy)},
4813 static const ClassDesc
4814 proxy_classes_to_check [] = {
4815 {"TransparentProxy", transparent_proxy_fields},
4816 {"RealProxy", real_proxy_fields},
4821 wait_handle_fields[] = {
4822 {"os_handle", G_STRUCT_OFFSET (MonoWaitHandle, handle)},
4823 {"disposed", G_STRUCT_OFFSET (MonoWaitHandle, disposed)},
4829 {"system_thread_handle", G_STRUCT_OFFSET (MonoThread, handle)},
4830 {"threadpool_thread", G_STRUCT_OFFSET (MonoThread, threadpool_thread)},
4831 {"state", G_STRUCT_OFFSET (MonoThread, state)},
4832 {"abort_exc", G_STRUCT_OFFSET (MonoThread, abort_exc)},
4833 {"abort_state", G_STRUCT_OFFSET (MonoThread, abort_state)},
4834 {"thread_id", G_STRUCT_OFFSET (MonoThread, tid)},
4838 static const ClassDesc
4839 threading_classes_to_check [] = {
4840 {"Thread", thread_fields},
4841 {"WaitHandle", wait_handle_fields},
4845 static const FieldDesc
4847 {"datetime_format", G_STRUCT_OFFSET (MonoCultureInfo, datetime_format)},
4848 {"number_format", G_STRUCT_OFFSET (MonoCultureInfo, number_format)},
4849 {"textinfo", G_STRUCT_OFFSET (MonoCultureInfo, textinfo)},
4850 {"name", G_STRUCT_OFFSET (MonoCultureInfo, name)},
4851 {"displayname", G_STRUCT_OFFSET (MonoCultureInfo, displayname)},
4852 {"englishname", G_STRUCT_OFFSET (MonoCultureInfo, englishname)},
4853 {"nativename", G_STRUCT_OFFSET (MonoCultureInfo, nativename)},
4854 {"iso3lang", G_STRUCT_OFFSET (MonoCultureInfo, iso3lang)},
4855 {"iso2lang", G_STRUCT_OFFSET (MonoCultureInfo, iso2lang)},
4856 {"icu_name", G_STRUCT_OFFSET (MonoCultureInfo, icu_name)},
4857 {"win3lang", G_STRUCT_OFFSET (MonoCultureInfo, win3lang)},
4858 {"compareinfo", G_STRUCT_OFFSET (MonoCultureInfo, compareinfo)},
4862 static const FieldDesc
4863 dtfinfo_fields[] = {
4864 {"amDesignator", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, AMDesignator)},
4865 {"pmDesignator", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, PMDesignator)},
4866 {"dayNames", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, DayNames)},
4867 {"monthNames", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, MonthNames)},
4871 static const FieldDesc
4873 {"decimalFormats", G_STRUCT_OFFSET (MonoNumberFormatInfo, decimalFormats)},
4874 {"currencySymbol", G_STRUCT_OFFSET (MonoNumberFormatInfo, currencySymbol)},
4875 {"percentSymbol", G_STRUCT_OFFSET (MonoNumberFormatInfo, percentSymbol)},
4876 {"positiveSign", G_STRUCT_OFFSET (MonoNumberFormatInfo, positiveSign)},
4880 static const FieldDesc
4881 compinfo_fields[] = {
4882 {"lcid", G_STRUCT_OFFSET (MonoCompareInfo, lcid)},
4883 {"ICU_collator", G_STRUCT_OFFSET (MonoCompareInfo, ICU_collator)},
4887 static const FieldDesc
4888 sortkey_fields[] = {
4889 {"str", G_STRUCT_OFFSET (MonoSortKey, str)},
4890 {"options", G_STRUCT_OFFSET (MonoSortKey, options)},
4891 {"key", G_STRUCT_OFFSET (MonoSortKey, key)},
4892 {"lcid", G_STRUCT_OFFSET (MonoSortKey, lcid)},
4896 static const ClassDesc
4897 globalization_classes_to_check [] = {
4898 {"CultureInfo", cinfo_fields},
4899 {"DateTimeFormatInfo", dtfinfo_fields},
4900 {"NumberFormatInfo", nfinfo_fields},
4901 {"CompareInfo", compinfo_fields},
4902 {"SortKey", sortkey_fields},
4906 static const FieldDesc
4907 safe_handle_fields[] ={
4908 {"handle", G_STRUCT_OFFSET (MonoSafeHandle, handle)},
4912 static const ClassDesc interop_classes_to_check [] = {
4913 {"SafeHandle", safe_handle_fields},
4919 const ClassDesc *types;
4922 static const NameSpaceDesc
4923 namespaces_to_check[] = {
4924 {"System.Runtime.Remoting.Proxies", proxy_classes_to_check},
4925 {"System.Runtime.Remoting.Messaging", messaging_classes_to_check},
4926 {"System.Reflection.Emit", emit_classes_to_check},
4927 {"System.Reflection", reflection_classes_to_check},
4928 {"System.Threading", threading_classes_to_check},
4929 {"System.Diagnostics", system_diagnostics_classes_to_check},
4930 {"System", system_classes_to_check},
4931 {"System.Globalization", globalization_classes_to_check},
4932 {"System.Runtime.InteropServices", interop_classes_to_check},
4937 check_corlib (MonoImage *corlib)
4940 MonoClassField *field;
4941 const FieldDesc *fdesc;
4942 const ClassDesc *cdesc;
4943 const NameSpaceDesc *ndesc;
4945 GString *result = NULL;
4947 for (ndesc = namespaces_to_check; ndesc->name; ++ndesc) {
4948 for (cdesc = ndesc->types; cdesc->name; ++cdesc) {
4949 klass = mono_class_from_name (corlib, ndesc->name, cdesc->name);
4952 result = g_string_new ("");
4953 g_string_append_printf (result, "Cannot find class %s\n", cdesc->name);
4956 mono_class_init (klass);
4958 * FIXME: we should also check the size of valuetypes, or
4959 * we're going to have trouble when we access them in arrays.
4961 if (klass->valuetype)
4962 struct_offset = sizeof (MonoObject);
4965 for (fdesc = cdesc->fields; fdesc->name; ++fdesc) {
4966 field = mono_class_get_field_from_name (klass, fdesc->name);
4967 if (!field || (field->offset != (fdesc->offset + struct_offset))) {
4969 result = g_string_new ("");
4970 g_string_append_printf (result, "field `%s' mismatch in class %s (%ld + %ld != %ld)\n", fdesc->name, cdesc->name, (long) fdesc->offset, (long)struct_offset, (long) (field?field->offset:-1));
4976 return g_string_free (result, FALSE);
4981 mono_verify_corlib () {
4982 return check_corlib (mono_defaults.corlib);