2 * metadata-verify.c: Metadata verfication support
5 * Mono Project (http://www.mono-project.com)
7 * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
9 #include <mono/metadata/object-internals.h>
10 #include <mono/metadata/verify.h>
11 #include <mono/metadata/verify-internals.h>
12 #include <mono/metadata/opcodes.h>
13 #include <mono/metadata/tabledefs.h>
14 #include <mono/metadata/reflection.h>
15 #include <mono/metadata/debug-helpers.h>
16 #include <mono/metadata/mono-endian.h>
17 #include <mono/metadata/metadata.h>
18 #include <mono/metadata/metadata-internals.h>
19 #include <mono/metadata/class-internals.h>
20 #include <mono/metadata/tokentype.h>
21 #include <mono/metadata/security-manager.h>
22 #include <mono/metadata/security-core-clr.h>
23 #include <mono/metadata/cil-coff.h>
24 #include <mono/metadata/attrdefs.h>
25 #include <mono/utils/strenc.h>
30 #ifndef DISABLE_VERIFIER
32 TODO add fail fast mode
33 TODO add PE32+ support
34 TODO verify the entry point RVA and content.
35 TODO load_section_table and load_data_directories must take PE32+ into account
36 TODO add section relocation support
37 TODO verify the relocation table, since we really don't use, no need so far.
38 TODO do full PECOFF resources verification
39 TODO verify in the CLI header entry point and resources
40 TODO implement null token typeref validation
41 TODO verify table wide invariants for typedef (sorting and uniqueness)
42 TODO implement proper authenticode data directory validation
43 TODO verify properties that require multiple tables to be valid
44 FIXME use subtraction based bounds checking to avoid overflows
45 FIXME get rid of metadata_streams and other fields from VerifyContext
48 #ifdef MONO_VERIFIER_DEBUG
49 #define VERIFIER_DEBUG(code) do { code; } while (0)
51 #define VERIFIER_DEBUG(code)
54 #define INVALID_OFFSET ((guint32)-1)
55 #define INVALID_ADDRESS 0xffffffff
65 RESOURCE_TABLE_IDX = 2,
66 CERTIFICATE_TABLE_IDX = 4,
67 RELOCATION_TABLE_IDX = 5,
81 #define INVALID_TABLE (0xFF)
82 /*format: number of bits, number of tables, tables{n. tables} */
83 const static unsigned char coded_index_desc[] = {
84 #define TYPEDEF_OR_REF_DESC (0)
91 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
98 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
106 MONO_TABLE_INTERFACEIMPL,
107 MONO_TABLE_MEMBERREF,
109 MONO_TABLE_DECLSECURITY,
112 MONO_TABLE_STANDALONESIG,
113 MONO_TABLE_MODULEREF,
116 MONO_TABLE_ASSEMBLYREF,
118 MONO_TABLE_EXPORTEDTYPE,
119 MONO_TABLE_MANIFESTRESOURCE,
120 MONO_TABLE_GENERICPARAM,
122 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
128 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
135 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
144 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
150 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
154 MONO_TABLE_MEMBERREF,
156 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
162 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
166 MONO_TABLE_ASSEMBLYREF,
167 MONO_TABLE_EXPORTEDTYPE,
169 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
175 MONO_TABLE_MEMBERREF,
178 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
182 MONO_TABLE_MODULEREF,
183 MONO_TABLE_ASSEMBLYREF,
186 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
196 guint32 translated_offset;
208 guint32 rellocationsRVA;
209 guint16 numberOfRelocations;
224 gboolean report_error;
225 gboolean report_warning;
228 DataDirectory data_directories [16];
229 guint32 section_count;
230 SectionHeader *sections;
232 OffsetAndSize metadata_streams [5]; //offset from begin of the image
235 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
237 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
238 vinfo->info.status = __status; \
239 vinfo->info.message = ( __msg); \
240 vinfo->exception_type = (__exception); \
241 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
244 #define ADD_WARNING(__ctx, __msg) \
246 if ((__ctx)->report_warning) { \
247 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
248 (__ctx)->valid = 0; \
253 #define ADD_ERROR(__ctx, __msg) \
255 if ((__ctx)->report_error) \
256 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
257 (__ctx)->valid = 0; \
261 #define FAIL(__ctx, __msg) \
263 if ((__ctx)->report_error) \
264 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
265 (__ctx)->valid = 0; \
269 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
271 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
273 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
274 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
276 #if SIZEOF_VOID_P == 4
277 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
279 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
282 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
283 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
286 dword_align (const char *ptr)
288 #if SIZEOF_VOID_P == 8
289 return (const char *) (((guint64) (ptr + 3)) & ~3);
291 return (const char *) (((guint32) (ptr + 3)) & ~3);
296 pe_signature_offset (VerifyContext *ctx)
298 return read32 (ctx->data + 0x3c);
302 pe_header_offset (VerifyContext *ctx)
304 return read32 (ctx->data + 0x3c) + 4;
308 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
312 if (rva + size < rva) //overflow
315 if (ctx->stage > STAGE_PE) {
316 MonoCLIImageInfo *iinfo = ctx->image->image_info;
317 const int top = iinfo->cli_section_count;
318 MonoSectionTable *tables = iinfo->cli_section_tables;
321 for (i = 0; i < top; i++) {
322 guint32 base = tables->st_virtual_address;
323 guint32 end = base + tables->st_raw_data_size;
325 if (rva >= base && rva + size <= end)
328 /*if ((addr >= tables->st_virtual_address) &&
329 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
331 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
341 for (i = 0; i < ctx->section_count; ++i) {
342 guint32 base = ctx->sections [i].baseRVA;
343 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
344 if (rva >= base && rva + size <= end)
351 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
353 if (dir->translated_offset > offset)
355 if (dir->size < size)
357 return offset + size <= dir->translated_offset + dir->size;
361 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
363 if (off->offset > offset)
366 if (off->size < size)
369 return offset + size <= off->offset + off->size;
373 translate_rva (VerifyContext *ctx, guint32 rva)
377 if (ctx->stage > STAGE_PE)
378 return mono_cli_rva_image_map (ctx->image, rva);
383 for (i = 0; i < ctx->section_count; ++i) {
384 guint32 base = ctx->sections [i].baseRVA;
385 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
386 if (rva >= base && rva <= end) {
387 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
389 return res >= ctx->size ? INVALID_OFFSET : res;
393 return INVALID_OFFSET;
397 verify_msdos_header (VerifyContext *ctx)
401 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
402 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
403 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
404 lfanew = pe_signature_offset (ctx);
405 if (lfanew > ctx->size - 4)
406 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
410 verify_pe_header (VerifyContext *ctx)
412 guint32 offset = pe_signature_offset (ctx);
413 const char *pe_header = ctx->data + offset;
414 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
415 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
419 if (offset > ctx->size - 20)
420 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
421 if (read16 (pe_header) != 0x14c)
422 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
426 verify_pe_optional_header (VerifyContext *ctx)
428 guint32 offset = pe_header_offset (ctx);
429 guint32 header_size, file_alignment;
430 const char *pe_header = ctx->data + offset;
431 const char *pe_optional_header = pe_header + 20;
433 header_size = read16 (pe_header + 16);
436 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
437 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
439 if (offset > ctx->size - header_size || header_size > ctx->size)
440 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
442 if (read16 (pe_optional_header) == 0x10b) {
443 if (header_size != 224)
444 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
446 /* LAMESPEC MS plays around this value and ignore it during validation
447 if (read32 (pe_optional_header + 28) != 0x400000)
448 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
449 if (read32 (pe_optional_header + 32) != 0x2000)
450 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
451 file_alignment = read32 (pe_optional_header + 36);
452 if (file_alignment != 0x200 && file_alignment != 0x1000)
453 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
454 /* All the junk in the middle is irrelevant, specially for mono. */
455 if (read32 (pe_optional_header + 92) > 0x10)
456 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
458 if (read16 (pe_optional_header) == 0x20B)
459 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
461 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
466 load_section_table (VerifyContext *ctx)
469 SectionHeader *sections;
470 guint32 offset = pe_header_offset (ctx);
471 const char *ptr = ctx->data + offset;
472 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
474 offset += 244;/*FIXME, this constant is different under PE32+*/
477 if (num_sections * 40 > ctx->size - offset)
478 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
480 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
481 for (i = 0; i < num_sections; ++i) {
482 sections [i].size = read32 (ptr + 8);
483 sections [i].baseRVA = read32 (ptr + 12);
484 sections [i].baseOffset = read32 (ptr + 20);
485 sections [i].rellocationsRVA = read32 (ptr + 24);
486 sections [i].numberOfRelocations = read16 (ptr + 32);
490 ptr = ctx->data + offset; /*reset it to the beggining*/
491 for (i = 0; i < num_sections; ++i) {
492 guint32 raw_size, flags;
493 if (sections [i].baseOffset == 0)
494 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
495 if (sections [i].baseOffset >= ctx->size)
496 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
497 if (sections [i].size > ctx->size - sections [i].baseOffset)
498 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
500 raw_size = read32 (ptr + 16);
501 if (raw_size < sections [i].size)
502 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
504 if (raw_size > ctx->size - sections [i].baseOffset)
505 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
507 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
508 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
510 flags = read32 (ptr + 36);
511 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
512 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
513 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
520 is_valid_data_directory (int i)
522 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
523 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
527 load_data_directories (VerifyContext *ctx)
529 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
530 const char *ptr = ctx->data + offset;
533 for (i = 0; i < 16; ++i) {
534 guint32 rva = read32 (ptr);
535 guint32 size = read32 (ptr + 4);
537 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
538 if (i == CERTIFICATE_TABLE_IDX) {
542 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
543 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
545 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
546 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
548 ctx->data_directories [i].rva = rva;
549 ctx->data_directories [i].size = size;
550 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
556 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
558 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
561 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
564 guint32 hint_table_rva;
566 import_rva = translate_rva (ctx, import_rva);
567 g_assert (import_rva != INVALID_OFFSET);
569 hint_table_rva = read32 (ctx->data + import_rva);
570 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
571 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
573 hint_table_rva = translate_rva (ctx, hint_table_rva);
574 g_assert (hint_table_rva != INVALID_OFFSET);
575 ptr = ctx->data + hint_table_rva + 2;
577 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
578 char name[SIZE_OF_CORMAIN];
579 memcpy (name, ptr, SIZE_OF_CORMAIN);
580 name [SIZE_OF_CORMAIN - 1] = 0;
581 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
586 verify_import_table (VerifyContext *ctx)
588 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
589 guint32 offset = it.translated_offset;
590 const char *ptr = ctx->data + offset;
591 guint32 name_rva, ilt_rva, iat_rva;
593 g_assert (offset != INVALID_OFFSET);
596 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
598 ilt_rva = read32 (ptr);
599 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
600 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
602 name_rva = read32 (ptr + 12);
603 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
604 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
606 iat_rva = read32 (ptr + 16);
608 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
609 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
611 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
612 ADD_ERROR (ctx, g_strdup_printf ("Import Address Table rva %x different from data directory entry %x", read32 (ptr + 16), ctx->data_directories [IAT_IDX].rva));
616 name_rva = translate_rva (ctx, name_rva);
617 g_assert (name_rva != INVALID_OFFSET);
618 ptr = ctx->data + name_rva;
620 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
621 char name[SIZE_OF_MSCOREE];
622 memcpy (name, ptr, SIZE_OF_MSCOREE);
623 name [SIZE_OF_MSCOREE - 1] = 0;
624 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
629 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
634 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
638 verify_resources_table (VerifyContext *ctx)
640 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
642 guint16 named_entries, id_entries;
643 const char *ptr, *root, *end;
649 ADD_ERROR (ctx, g_strdup_printf ("Resource section is too small, must be at least 16 bytes long but it's %d long", it.size));
651 offset = it.translated_offset;
652 root = ptr = ctx->data + offset;
653 end = root + it.size;
655 g_assert (offset != INVALID_OFFSET);
657 named_entries = read16 (ptr + 12);
658 id_entries = read16 (ptr + 14);
660 if ((named_entries + id_entries) * 8 + 16 > it.size)
661 ADD_ERROR (ctx, g_strdup_printf ("Resource section is too small, the number of entries (%d) doesn't fit on it's size %d", named_entries + id_entries, it.size));
663 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
664 if (named_entries || id_entries)
665 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
669 /*----------nothing from here on can use data_directory---*/
672 get_data_dir (VerifyContext *ctx, int idx)
674 MonoCLIImageInfo *iinfo = ctx->image->image_info;
675 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
679 res.rva = entry->rva;
680 res.size = entry->size;
681 res.translated_offset = translate_rva (ctx, res.rva);
686 verify_cli_header (VerifyContext *ctx)
688 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
694 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
697 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
699 offset = it.translated_offset;
700 ptr = ctx->data + offset;
702 g_assert (offset != INVALID_OFFSET);
704 if (read16 (ptr) != 72)
705 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
707 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
708 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
711 if (!read32 (ptr + 8) || !read32 (ptr + 12))
712 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
714 if ((read32 (ptr + 16) & ~0x0001000B) != 0)
715 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
718 for (i = 0; i < 6; ++i) {
719 guint32 rva = read32 (ptr);
720 guint32 size = read32 (ptr + 4);
722 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
723 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
728 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
733 pad4 (guint32 offset)
735 if (offset & 0x3) //pad to the next 4 byte boundary
736 offset = (offset & ~0x3) + 4;
741 verify_metadata_header (VerifyContext *ctx)
744 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
748 offset = it.translated_offset;
749 ptr = ctx->data + offset;
750 g_assert (offset != INVALID_OFFSET);
752 //build a directory entry for the metadata root
754 it.rva = read32 (ptr);
756 it.size = read32 (ptr);
757 it.translated_offset = offset = translate_rva (ctx, it.rva);
759 ptr = ctx->data + offset;
760 g_assert (offset != INVALID_OFFSET);
763 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
765 if (read32 (ptr) != 0x424A5342)
766 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
768 offset = pad4 (offset + 16 + read32 (ptr + 12));
770 if (!bounds_check_datadir (&it, offset, 4))
771 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least %d bytes required for flags decoding)", it.size, offset + 4 - it.translated_offset));
773 ptr = ctx->data + offset; //move to streams header
775 if (read16 (ptr + 2) < 3)
776 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob"));
781 for (i = 0; i < 5; ++i) {
782 guint32 stream_off, stream_size;
783 int string_size, stream_idx;
785 if (!bounds_check_datadir (&it, offset, 8))
786 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small for initial decode of stream header %d, missing %d bytes", i, offset + 9 - it.translated_offset));
788 stream_off = it.translated_offset + read32 (ptr);
789 stream_size = read32 (ptr + 4);
791 if (!bounds_check_datadir (&it, stream_off, stream_size))
792 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
797 for (string_size = 0; string_size < 32; ++string_size) {
798 if (!bounds_check_datadir (&it, offset++, 1))
799 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
800 if (!ptr [string_size])
804 if (ptr [string_size])
805 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
807 if (!strncmp ("#Strings", ptr, 9))
808 stream_idx = STRINGS_STREAM;
809 else if (!strncmp ("#US", ptr, 4))
810 stream_idx = USER_STRINGS_STREAM;
811 else if (!strncmp ("#Blob", ptr, 6))
812 stream_idx = BLOB_STREAM;
813 else if (!strncmp ("#GUID", ptr, 6))
814 stream_idx = GUID_STREAM;
815 else if (!strncmp ("#~", ptr, 3))
816 stream_idx = TILDE_STREAM;
818 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
820 if (ctx->metadata_streams [stream_idx].offset != 0)
821 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
823 ctx->metadata_streams [stream_idx].offset = stream_off;
824 ctx->metadata_streams [stream_idx].size = stream_size;
826 offset = pad4 (offset);
827 ptr = ctx->data + offset;
830 if (!ctx->metadata_streams [TILDE_STREAM].size)
831 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
832 if (!ctx->metadata_streams [GUID_STREAM].size)
833 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
834 if (!ctx->metadata_streams [BLOB_STREAM].size)
835 ADD_ERROR (ctx, g_strdup_printf ("Metadata blob stream missing"));
840 verify_tables_schema (VerifyContext *ctx)
842 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
843 unsigned offset = tables_area.offset;
844 const char *ptr = ctx->data + offset;
845 guint64 valid_tables;
849 //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
850 if (tables_area.size < 24)
851 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
853 //printf ("ptr %x %x\n", ptr[4], ptr[5]);
854 if (ptr [4] != 2 && ptr [4] != 1)
855 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
857 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
859 if ((ptr [6] & ~0x7) != 0)
860 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata heap sizes 0x%02x, only bits 0, 1 and 2 can be set", ((unsigned char *) ptr) [6]));
862 valid_tables = read64 (ptr + 8);
864 for (i = 0; i < 64; ++i) {
865 if (!(valid_tables & ((guint64)1 << i)))
868 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
869 Unused: 0x1E 0x1F 0x2D-0x3F
870 We don't care about the MS extensions.*/
871 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
872 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
873 if (i == 0x1E || i == 0x1F || i >= 0x2D)
874 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
878 if (tables_area.size < 24 + count * 4)
879 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for decoding row counts (requires %d bytes)", tables_area.size, 24 + count * 4));
882 for (i = 0; i < 64; ++i) {
883 if (valid_tables & ((guint64)1 << i)) {
884 guint32 row_count = read32 (ptr);
885 if (row_count > (1 << 24) - 1)
886 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
892 /*----------nothing from here on can use data_directory or metadata_streams ---*/
895 get_col_offset (VerifyContext *ctx, int table, int column)
897 guint32 bitfield = ctx->image->tables [table].size_bitfield;
901 offset += mono_metadata_table_size (bitfield, column);
907 get_col_size (VerifyContext *ctx, int table, int column)
909 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
913 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
916 res.offset = header->data - ctx->data;
917 res.size = header->size;
923 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
925 OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
927 const char *data = ctx->data + strings.offset;
929 if (offset >= strings.size)
931 if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing
934 if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
936 return allow_empty || length > 0;
940 is_valid_string (VerifyContext *ctx, guint32 offset)
942 return is_valid_string_full (ctx, offset, TRUE);
946 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
948 return is_valid_string_full (ctx, offset, FALSE);
952 is_valid_guid (VerifyContext *ctx, guint32 offset)
954 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
955 return guids.size >= 8 && guids.size - 8 >= offset;
959 get_coded_index_token (int token_kind, guint32 coded_token)
961 guint32 bits = coded_index_desc [token_kind];
962 return coded_token >> bits;
966 get_coded_index_table (int kind, guint32 coded_token)
968 guint32 idx, bits = coded_index_desc [kind];
970 idx = coded_token & ((1 << bits) - 1);
971 return coded_index_desc [kind + idx];
975 make_coded_token (int kind, guint32 table, guint32 table_idx)
977 guint32 bits = coded_index_desc [kind++];
978 guint32 tables = coded_index_desc [kind++];
980 for (i = 0; i < tables; ++i) {
981 if (coded_index_desc [kind++] == table)
982 return ((table_idx + 1) << bits) | i;
984 g_assert_not_reached ();
989 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
991 guint32 bits = coded_index_desc [token_kind++];
992 guint32 table_count = coded_index_desc [token_kind++];
993 guint32 table = coded_token & ((1 << bits) - 1);
994 guint32 token = coded_token >> bits;
996 if (table >= table_count)
999 /*token_kind points to the first table idx*/
1000 table = coded_index_desc [token_kind + table];
1002 if (table == INVALID_TABLE)
1004 return token <= ctx->image->tables [table].rows;
1011 MonoTableInfo *table;
1015 token_locator (const void *a, const void *b)
1017 RowLocator *loc = (RowLocator *)a;
1018 unsigned const char *row = (unsigned const char *)b;
1019 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1021 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1022 return (int)loc->token - (int)token;
1026 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1028 MonoTableInfo *tinfo = &ctx->image->tables [table];
1030 const char *res, *base;
1031 locator.token = coded_token;
1032 locator.col_offset = get_col_offset (ctx, table, column);
1033 locator.col_size = get_col_size (ctx, table, column);
1034 locator.table = tinfo;
1038 VERIFIER_DEBUG ( printf ("looking token %x table %d col %d rsize %d roff %d\n", coded_token, table, column, locator.col_size, locator.col_offset) );
1039 res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1043 return (res - base) / tinfo->row_size;
1046 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1048 get_string_ptr (VerifyContext *ctx, guint offset)
1050 return ctx->image->heap_strings.data + offset;
1053 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1055 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1058 return strcmp (str, "");
1060 return strcmp (str, get_string_ptr (ctx, offset));
1064 mono_verifier_is_corlib (MonoImage *image)
1066 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
1067 TRUE : mono_security_core_clr_is_platform_image (image);
1069 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1073 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1075 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1079 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1082 const unsigned char *ptr = (const unsigned char *)_ptr;
1090 if ((b & 0x80) == 0) {
1093 } else if ((b & 0x40) == 0) {
1097 *value = ((b & 0x3f) << 8 | ptr [1]);
1102 *value = ((b & 0x1f) << 24) |
1112 decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
1114 MonoStreamHeader blob = ctx->image->heap_blob;
1115 guint32 value, enc_size;
1117 if (offset >= blob.size)
1120 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1123 if (offset + enc_size + value < offset)
1126 if (offset + enc_size + value > blob.size)
1130 *first_byte = blob.data + offset + enc_size;
1135 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1137 const char *ptr = *_ptr;
1138 if (ptr + size > limit)
1142 *dest = *((guint8*)ptr);
1146 *dest = read16 (ptr);
1150 *dest = read32 (ptr);
1159 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1162 const char *ptr = *_ptr;
1163 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1168 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1169 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1170 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1171 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1174 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1177 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1180 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1182 const char *ptr = *_ptr;
1187 if (!safe_read8 (type, ptr, end))
1188 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1190 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1195 if (!safe_read_cint (token, ptr, end))
1196 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1198 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1199 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1207 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1209 const char *ptr = *_ptr;
1211 unsigned size, num, i;
1213 if (!safe_read8 (val, ptr, end))
1214 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1217 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1219 if (!safe_read_cint (size, ptr, end))
1220 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1222 for (i = 0; i < size; ++i) {
1223 if (!safe_read_cint (num, ptr, end))
1224 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1227 if (!safe_read_cint (size, ptr, end))
1228 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1230 for (i = 0; i < size; ++i) {
1231 if (!safe_read_cint (num, ptr, end))
1232 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1240 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1242 const char *ptr = *_ptr;
1244 unsigned count, token, i;
1246 if (!safe_read8 (type, ptr, end))
1247 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1249 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1250 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1252 if (!safe_read_cint (token, ptr, end))
1253 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1255 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1256 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1258 if (!safe_read_cint (count, ptr, end))
1259 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1262 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1264 for (i = 0; i < count; ++i) {
1265 if (!parse_type (ctx, &ptr, end))
1266 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1273 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1275 const char *ptr = *_ptr;
1279 if (!safe_read8 (type, ptr, end))
1280 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1282 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1283 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1284 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1285 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1286 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1290 if (!parse_custom_mods (ctx, &ptr, end))
1291 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1293 if (!safe_read8 (type, ptr, end))
1294 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1296 if (type != MONO_TYPE_VOID) {
1298 if (!parse_type (ctx, &ptr, end))
1299 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1303 case MONO_TYPE_VALUETYPE:
1304 case MONO_TYPE_CLASS:
1305 if (!safe_read_cint (token, ptr, end))
1306 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1308 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1309 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1313 case MONO_TYPE_MVAR:
1314 if (!safe_read_cint (token, ptr, end))
1315 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1318 case MONO_TYPE_ARRAY:
1319 if (!parse_type (ctx, &ptr, end))
1320 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1321 if (!parse_array_shape (ctx, &ptr, end))
1322 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1325 case MONO_TYPE_GENERICINST:
1326 if (!parse_generic_inst (ctx, &ptr, end))
1327 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1330 case MONO_TYPE_FNPTR:
1331 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1332 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1335 case MONO_TYPE_SZARRAY:
1336 if (!parse_custom_mods (ctx, &ptr, end))
1337 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1338 if (!parse_type (ctx, &ptr, end))
1339 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1347 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1352 if (!parse_custom_mods (ctx, _ptr, end))
1356 if (!safe_read8 (type, ptr, end))
1357 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1359 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1364 //it's a byref, update the cursor ptr
1365 if (type == MONO_TYPE_BYREF)
1368 return parse_type (ctx, _ptr, end);
1372 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1377 if (!parse_custom_mods (ctx, _ptr, end))
1381 if (!safe_read8 (type, ptr, end))
1382 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1384 if (type == MONO_TYPE_TYPEDBYREF) {
1389 //it's a byref, update the cursor ptr
1390 if (type == MONO_TYPE_BYREF)
1393 return parse_type (ctx, _ptr, end);
1397 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1400 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1401 const char *ptr = *_ptr;
1402 gboolean saw_sentinel = FALSE;
1404 if (!safe_read8 (cconv, ptr, end))
1405 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1408 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1410 if (allow_unmanaged) {
1411 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1412 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1413 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1414 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1416 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1417 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1419 if ((cconv & 0x10) && gparam_count == 0)
1420 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1422 if (allow_unmanaged && (cconv & 0x10))
1423 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1425 if (!safe_read_cint (param_count, ptr, end))
1426 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1428 if (!parse_return_type (ctx, &ptr, end))
1429 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1431 for (i = 0; i < param_count; ++i) {
1432 if (allow_sentinel) {
1433 if (!safe_read8 (type, ptr, end))
1434 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1436 if (type == MONO_TYPE_SENTINEL) {
1437 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1438 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1441 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1443 saw_sentinel = TRUE;
1449 if (!parse_param (ctx, &ptr, end))
1450 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1458 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1461 unsigned param_count = 0, i;
1462 const char *ptr = *_ptr;
1464 if (!safe_read8 (sig, ptr, end))
1465 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1467 if (sig != 0x08 && sig != 0x28)
1468 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1470 if (!safe_read_cint (param_count, ptr, end))
1471 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1473 if (!parse_custom_mods (ctx, &ptr, end))
1476 if (!parse_type (ctx, &ptr, end))
1477 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1479 for (i = 0; i < param_count; ++i) {
1480 if (!parse_type (ctx, &ptr, end))
1481 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1489 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1491 const char *ptr = *_ptr;
1492 unsigned signature = 0;
1494 if (!safe_read8 (signature, ptr, end))
1495 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1497 if (signature != 0x06)
1498 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1500 if (!parse_custom_mods (ctx, &ptr, end))
1503 if (safe_read8 (signature, ptr, end)) {
1504 if (signature != MONO_TYPE_BYREF)
1509 return parse_type (ctx, _ptr, end);
1513 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1516 unsigned locals_count = 0, i;
1517 const char *ptr = *_ptr;
1519 if (!safe_read8 (sig, ptr, end))
1520 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1523 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1525 if (!safe_read_cint (locals_count, ptr, end))
1526 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1528 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1529 if (locals_count == 0)
1530 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1533 for (i = 0; i < locals_count; ++i) {
1534 if (!safe_read8 (sig, ptr, end))
1535 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1537 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1538 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1539 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1540 if (!safe_read8 (sig, ptr, end))
1541 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1544 if (sig == MONO_TYPE_BYREF) {
1545 if (!safe_read8 (sig, ptr, end))
1546 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1547 if (sig == MONO_TYPE_TYPEDBYREF)
1548 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1551 if (sig == MONO_TYPE_TYPEDBYREF)
1556 if (!parse_type (ctx, &ptr, end))
1557 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1565 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1568 unsigned signature = 0;
1569 const char *ptr = NULL, *end;
1571 if (!decode_signature_header (ctx, offset, &size, &ptr))
1572 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1575 if (!safe_read8 (signature, ptr, end))
1576 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1579 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1582 return parse_field (ctx, &ptr, end);
1586 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1589 const char *ptr = NULL, *end;
1591 if (!decode_signature_header (ctx, offset, &size, &ptr))
1592 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1595 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1599 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1602 unsigned signature = 0;
1603 const char *ptr = NULL, *end;
1605 if (!decode_signature_header (ctx, offset, &size, &ptr))
1606 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1609 if (!safe_read8 (signature, ptr, end))
1610 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1613 if (signature == 0x06)
1614 return parse_field (ctx, &ptr, end);
1616 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1620 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1623 unsigned prolog = 0;
1624 const char *ptr = NULL, *end;
1629 if (!decode_signature_header (ctx, offset, &size, &ptr))
1630 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1633 if (!safe_read16 (prolog, ptr, end))
1634 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1637 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1643 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1645 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1646 //TODO do proper verification
1647 return blob.size >= 1 && blob.size - 1 >= offset;
1651 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1653 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1654 //TODO do proper verification
1655 return blob.size >= 1 && blob.size - 1 >= offset;
1659 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1662 unsigned signature = 0;
1663 const char *ptr = NULL, *end;
1665 if (!decode_signature_header (ctx, offset, &size, &ptr))
1666 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1669 if (!safe_read8 (signature, ptr, end))
1670 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1673 if (signature == 0x07)
1674 return parse_locals_signature (ctx, &ptr, end);
1675 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1679 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1682 const char *ptr = NULL, *end;
1684 if (!decode_signature_header (ctx, offset, &size, &ptr))
1685 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
1688 return parse_property_signature (ctx, &ptr, end);
1692 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1695 const char *ptr = NULL, *end;
1699 if (!decode_signature_header (ctx, offset, &size, &ptr))
1700 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
1703 if (!parse_custom_mods (ctx, &ptr, end))
1706 if (!safe_read8 (type, ptr, end))
1707 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
1709 if (type == MONO_TYPE_BYREF) {
1710 if (!safe_read8 (type, ptr, end))
1711 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
1712 if (type == MONO_TYPE_TYPEDBYREF)
1713 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
1716 if (type == MONO_TYPE_TYPEDBYREF)
1720 return parse_type (ctx, &ptr, end);
1724 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1727 const char *ptr = NULL, *end;
1729 unsigned count = 0, i;
1731 if (!decode_signature_header (ctx, offset, &size, &ptr))
1732 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
1735 if (!safe_read8 (type, ptr, end))
1736 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
1739 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
1741 if (!safe_read_cint (count, ptr, end))
1742 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
1745 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
1747 for (i = 0; i < count; ++i) {
1748 if (!parse_type (ctx, &ptr, end))
1749 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
1755 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
1757 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1758 guint32 entry_size, bytes;
1760 if (blob.size < offset)
1763 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1766 if (entry_size < minsize)
1769 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
1771 entry_size += bytes;
1773 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
1777 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1779 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1780 guint32 size, entry_size, bytes;
1782 if (blob.size < offset)
1783 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
1785 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1786 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
1788 if (type == MONO_TYPE_STRING) {
1789 //String is encoded as: compressed_int:len len *bytes
1792 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
1793 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
1799 case MONO_TYPE_BOOLEAN:
1804 case MONO_TYPE_CHAR:
1812 case MONO_TYPE_CLASS:
1822 g_assert_not_reached ();
1825 if (size != entry_size)
1826 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
1830 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
1831 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
1833 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
1834 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
1838 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
1839 //only 0x01, 0x40 and 0x80 are allowed
1840 #define SECTION_HEADER_INVALID_FLAGS 0x3E
1843 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1845 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
1846 unsigned header = 0;
1847 unsigned fat_header = 0, size = 0, max_stack;
1848 const char *ptr = NULL, *end;
1850 if (offset == INVALID_ADDRESS)
1851 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
1853 ptr = ctx->data + offset;
1854 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
1856 if (!safe_read8 (header, ptr, end))
1857 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
1859 switch (header & 0x3) {
1862 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
1865 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
1866 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
1871 if (!safe_read16 (fat_header, ptr, end))
1872 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
1874 size = (fat_header >> 12) & 0xF;
1876 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
1878 if (!safe_read16 (max_stack, ptr, end))
1879 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
1881 if (!safe_read32 (code_size, ptr, end))
1882 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
1884 if (!safe_read32 (local_vars_tok, ptr, end))
1885 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
1887 if (local_vars_tok) {
1888 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
1889 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
1890 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
1891 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
1894 if (fat_header & FAT_HEADER_INVALID_FLAGS)
1895 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
1897 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
1898 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
1900 if (!(fat_header & 0x08))
1906 unsigned section_header = 0, section_size = 0;
1909 ptr = dword_align (ptr);
1910 if (!safe_read32 (section_header, ptr, end))
1911 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
1913 if (section_header & SECTION_HEADER_INVALID_FLAGS)
1914 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
1916 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
1917 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
1919 if (section_size < 4)
1920 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
1922 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
1923 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
1925 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
1926 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
1928 LAMEIMPL: MS emits section_size without accounting for header size.
1929 Mono does as the spec says. section_size is header + section
1930 MS's peverify happily accepts both.
1932 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
1933 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid EH section size %d, it's not of the expected size %d", section_size, clauses * (is_fat ? 24 : 12)));
1935 /* only verify the class token is verified as the rest is done by the IL verifier*/
1936 for (i = 0; i < clauses; ++i) {
1937 unsigned flags = *(unsigned char*)ptr;
1938 unsigned class_token = 0;
1939 ptr += (is_fat ? 20 : 8);
1940 if (!safe_read32 (class_token, ptr, end))
1941 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
1942 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
1943 guint table = mono_metadata_token_table (class_token);
1944 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
1945 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
1946 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
1947 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
1952 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
1959 verify_module_table (VerifyContext *ctx)
1961 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1962 guint32 data [MONO_MODULE_SIZE];
1964 if (table->rows != 1)
1965 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1967 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1969 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1970 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1972 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1973 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1975 if (data [MONO_MODULE_ENC] != 0)
1976 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1978 if (data [MONO_MODULE_ENCBASE] != 0)
1979 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1983 verify_typeref_table (VerifyContext *ctx)
1985 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1986 guint32 data [MONO_TYPEREF_SIZE];
1989 for (i = 0; i < table->rows; ++i) {
1990 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1991 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1992 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1994 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1995 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1997 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1998 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
2000 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2001 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
2005 /*bits 9,11,14,15,19,21,24-31 */
2006 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2008 verify_typedef_table (VerifyContext *ctx)
2010 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2011 guint32 data [MONO_TYPEDEF_SIZE];
2012 guint32 fieldlist = 1, methodlist = 1, visibility;
2015 if (table->rows == 0)
2016 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2018 for (i = 0; i < table->rows; ++i) {
2019 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2020 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2021 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2023 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2024 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2026 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2027 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2029 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2030 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2032 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2033 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2035 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2036 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2038 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2039 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2041 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2042 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2044 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2045 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2046 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2047 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2049 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2050 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2052 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2053 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2055 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2056 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x can't be smaller than of previous row 0x%08x", i, data [MONO_TYPEDEF_FIELD_LIST], fieldlist));
2058 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2059 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2061 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2062 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2064 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2065 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x can't be smaller than of previous row 0x%08x", i, data [MONO_TYPEDEF_METHOD_LIST], methodlist));
2067 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2068 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2073 verify_typedef_table_full (VerifyContext *ctx)
2075 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2076 guint32 data [MONO_TYPEDEF_SIZE];
2079 if (table->rows == 0)
2080 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2082 for (i = 0; i < table->rows; ++i) {
2083 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2086 if (data [MONO_TYPEDEF_EXTENDS] != 0)
2087 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2091 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2092 if (data [MONO_TYPEDEF_EXTENDS])
2093 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2095 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2096 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2100 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2103 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2111 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2113 verify_field_table (VerifyContext *ctx)
2115 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2116 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2119 module_field_list = (guint32)-1;
2120 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2121 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2122 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2125 for (i = 0; i < table->rows; ++i) {
2126 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2127 flags = data [MONO_FIELD_FLAGS];
2129 if (flags & INVALID_FIELD_FLAG_BITS)
2130 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2132 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2133 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2135 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2136 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2138 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2139 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2141 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2142 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2144 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2145 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2146 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2148 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2149 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2150 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2152 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2153 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2154 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2156 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2157 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2158 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2160 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2161 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2163 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2164 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2166 //TODO verify contant flag
2168 if (i + 1 < module_field_list) {
2169 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2170 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2171 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2172 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2173 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2179 verify_field_table_full (VerifyContext *ctx)
2181 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2182 guint32 data [MONO_FIELD_SIZE];
2185 for (i = 0; i < table->rows; ++i) {
2186 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2188 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2189 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2193 /*bits 6,8,9,10,11,13,14,15*/
2194 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2196 verify_method_table (VerifyContext *ctx)
2198 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2199 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2200 guint32 paramlist = 1;
2201 gboolean is_ctor, is_cctor;
2205 module_method_list = (guint32)-1;
2206 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2207 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2208 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2211 for (i = 0; i < table->rows; ++i) {
2212 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2213 rva = data [MONO_METHOD_RVA];
2214 implflags = data [MONO_METHOD_IMPLFLAGS];
2215 flags = data [MONO_METHOD_FLAGS];
2216 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2217 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2220 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2221 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2224 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2226 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2227 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2229 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2230 is_ctor = !strcmp (".ctor", name);
2231 is_cctor = !strcmp (".cctor", name);
2233 if ((is_ctor || is_cctor) &&
2234 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2235 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2237 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2238 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2240 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2241 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2242 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2243 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2244 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2247 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2248 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2250 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2251 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2253 //XXX no checks against cas stuff 10,11,12,13)
2255 //TODO check iface with .ctor (15,16)
2257 if (i + 1 < module_method_list) {
2258 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2259 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2260 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2261 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2262 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2263 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2266 //TODO check valuetype for synchronized
2268 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2269 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2271 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2272 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2273 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2274 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2275 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2278 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2279 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2280 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2282 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2283 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2285 //TODO check signature contents
2288 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2289 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2290 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2291 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2293 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2294 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2297 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2299 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2300 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2301 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2303 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2304 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2306 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2307 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2309 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2310 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2312 if (data [MONO_METHOD_PARAMLIST] == 0)
2313 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2315 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2316 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x can't be smaller than of previous row 0x%08x", i, data [MONO_METHOD_PARAMLIST], paramlist));
2318 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2319 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2321 paramlist = data [MONO_METHOD_PARAMLIST];
2327 verify_method_table_full (VerifyContext *ctx)
2329 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2330 guint32 data [MONO_METHOD_SIZE], rva;
2333 for (i = 0; i < table->rows; ++i) {
2334 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2335 rva = data [MONO_METHOD_RVA];
2337 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2338 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2340 if (rva && !is_valid_method_header (ctx, rva))
2341 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2346 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2348 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2349 guint32 row = *current_method;
2350 guint32 paramlist, tmp;
2353 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2354 while (row < table->rows) {
2355 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2356 if (tmp > paramlist) {
2357 *current_method = row;
2358 return tmp - paramlist;
2363 /*no more methods, all params apply to the last one*/
2364 *current_method = table->rows;
2369 #define INVALID_PARAM_FLAGS_BITS ((1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15))
2371 verify_param_table (VerifyContext *ctx)
2373 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2374 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2375 gboolean first_param = TRUE;
2378 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2379 if (table->rows > 0)
2380 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2384 remaining_params = get_next_param_count (ctx, ¤t_method);
2386 for (i = 0; i < table->rows; ++i) {
2387 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2388 flags = data [MONO_PARAM_FLAGS];
2390 if (flags & INVALID_PARAM_FLAGS_BITS)
2391 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2393 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2394 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2395 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2397 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2398 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2401 if ((flags & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL) && search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_PARAM, i)) == -1)
2402 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2404 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2405 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2407 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2408 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2410 first_param = FALSE;
2411 sequence = data [MONO_PARAM_SEQUENCE];
2412 if (--remaining_params == 0) {
2413 remaining_params = get_next_param_count (ctx, ¤t_method);
2420 verify_interfaceimpl_table (VerifyContext *ctx)
2422 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2423 guint32 data [MONO_INTERFACEIMPL_SIZE];
2426 for (i = 0; i < table->rows; ++i) {
2427 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2428 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2429 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2431 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2432 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2434 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2435 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2440 verify_memberref_table (VerifyContext *ctx)
2442 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2443 guint32 data [MONO_MEMBERREF_SIZE];
2446 for (i = 0; i < table->rows; ++i) {
2447 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2449 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2450 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2452 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2453 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2455 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2456 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2458 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2459 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2465 verify_memberref_table_full (VerifyContext *ctx)
2467 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2468 guint32 data [MONO_MEMBERREF_SIZE];
2471 for (i = 0; i < table->rows; ++i) {
2472 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2474 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2475 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2480 verify_constant_table (VerifyContext *ctx)
2482 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2483 guint32 data [MONO_CONSTANT_SIZE], type;
2486 for (i = 0; i < table->rows; ++i) {
2487 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2488 type = data [MONO_CONSTANT_TYPE];
2490 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2491 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2493 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2494 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2496 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2497 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2499 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2500 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2505 verify_cattr_table (VerifyContext *ctx)
2507 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2508 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2511 for (i = 0; i < table->rows; ++i) {
2512 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2514 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2515 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2517 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2518 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2520 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2521 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2526 verify_cattr_table_full (VerifyContext *ctx)
2528 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2529 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2532 for (i = 0; i < table->rows; ++i) {
2533 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2535 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2536 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2541 verify_field_marshal_table (VerifyContext *ctx)
2543 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2544 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2547 for (i = 0; i < table->rows; ++i) {
2548 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2550 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2551 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2553 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2554 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2556 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2557 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2559 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2560 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2565 verify_field_marshal_table_full (VerifyContext *ctx)
2567 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2568 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2571 for (i = 0; i < table->rows; ++i) {
2572 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2574 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2575 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2580 verify_decl_security_table (VerifyContext *ctx)
2582 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2583 guint32 data [MONO_DECL_SECURITY_SIZE];
2586 for (i = 0; i < table->rows; ++i) {
2587 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2589 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2590 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2592 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2593 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2595 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2596 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2601 verify_decl_security_table_full (VerifyContext *ctx)
2603 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2604 guint32 data [MONO_DECL_SECURITY_SIZE];
2607 for (i = 0; i < table->rows; ++i) {
2608 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2610 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2611 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2616 verify_class_layout_table (VerifyContext *ctx)
2618 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2619 guint32 data [MONO_CLASS_LAYOUT_SIZE];
2622 for (i = 0; i < table->rows; ++i) {
2623 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2625 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2626 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2628 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2640 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2646 verify_field_layout_table (VerifyContext *ctx)
2648 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2649 guint32 data [MONO_FIELD_LAYOUT_SIZE];
2652 for (i = 0; i < table->rows; ++i) {
2653 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2655 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2656 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2661 verify_standalonesig_table (VerifyContext *ctx)
2663 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2664 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2667 for (i = 0; i < table->rows; ++i) {
2668 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2670 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
2671 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2676 verify_standalonesig_table_full (VerifyContext *ctx)
2678 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2679 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2682 for (i = 0; i < table->rows; ++i) {
2683 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2685 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2686 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2691 verify_eventmap_table (VerifyContext *ctx)
2693 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2694 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2697 for (i = 0; i < table->rows; ++i) {
2698 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2700 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2701 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2703 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2704 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2706 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2710 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2712 verify_event_table (VerifyContext *ctx)
2714 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2715 guint32 data [MONO_EVENT_SIZE];
2718 for (i = 0; i < table->rows; ++i) {
2719 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2721 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2722 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2724 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2725 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2727 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2728 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2733 verify_event_table_full (VerifyContext *ctx)
2735 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2736 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2737 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2738 gboolean found_add, found_remove;
2741 for (i = 0; i < table->rows; ++i) {
2742 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2744 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2745 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2747 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2749 //first we move to the first row for this event
2751 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2755 //now move forward looking for AddOn and RemoveOn rows
2756 found_add = found_remove = FALSE;
2757 while (idx < sema_table->rows) {
2758 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2759 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2761 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2763 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2764 found_remove = TRUE;
2765 if (found_add && found_remove)
2771 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2773 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2778 verify_propertymap_table (VerifyContext *ctx)
2780 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2781 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2784 for (i = 0; i < table->rows; ++i) {
2785 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2787 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2788 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2790 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2791 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2793 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2797 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2799 verify_property_table (VerifyContext *ctx)
2801 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2802 guint32 data [MONO_PROPERTY_SIZE];
2805 for (i = 0; i < table->rows; ++i) {
2806 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2808 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2809 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2811 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2812 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2814 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2815 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2817 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2818 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2819 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2825 verify_methodimpl_table (VerifyContext *ctx)
2827 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2828 guint32 data [MONO_METHODIMPL_SIZE];
2831 for (i = 0; i < table->rows; ++i) {
2832 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2834 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2835 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2837 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2838 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2840 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2841 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2843 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2844 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2846 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2847 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2852 verify_moduleref_table (VerifyContext *ctx)
2854 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2855 guint32 data [MONO_MODULEREF_SIZE];
2858 for (i = 0; i < table->rows; ++i) {
2859 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2861 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2862 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2867 verify_typespec_table (VerifyContext *ctx)
2869 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2870 guint32 data [MONO_TYPESPEC_SIZE];
2873 for (i = 0; i < table->rows; ++i) {
2874 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2876 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
2877 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2882 verify_typespec_table_full (VerifyContext *ctx)
2884 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2885 guint32 data [MONO_TYPESPEC_SIZE];
2888 for (i = 0; i < table->rows; ++i) {
2889 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2891 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2892 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2896 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
2898 verify_implmap_table (VerifyContext *ctx)
2900 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2901 guint32 data [MONO_IMPLMAP_SIZE], cconv;
2904 for (i = 0; i < table->rows; ++i) {
2905 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2907 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2908 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2910 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2911 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2912 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2914 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2915 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2917 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2918 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2920 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2921 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2923 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2924 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2926 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
2927 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2932 verify_fieldrva_table (VerifyContext *ctx)
2934 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2935 guint32 data [MONO_FIELD_RVA_SIZE];
2938 for (i = 0; i < table->rows; ++i) {
2939 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2941 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2942 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2944 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2945 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2949 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
2951 verify_assembly_table (VerifyContext *ctx)
2953 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2954 guint32 data [MONO_ASSEMBLY_SIZE], hash;
2957 if (table->rows > 1)
2958 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2960 for (i = 0; i < table->rows; ++i) {
2961 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2963 hash = data [MONO_ASSEMBLY_HASH_ALG];
2964 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2965 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2967 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2968 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2970 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
2971 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2973 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2974 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2976 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2977 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2981 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2983 verify_assemblyref_table (VerifyContext *ctx)
2985 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2986 guint32 data [MONO_ASSEMBLYREF_SIZE];
2989 for (i = 0; i < table->rows; ++i) {
2990 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2992 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2993 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2995 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
2996 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2998 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2999 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3001 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3002 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3004 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3005 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3009 #define INVALID_FILE_FLAGS_BITS ~(1)
3011 verify_file_table (VerifyContext *ctx)
3013 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3014 guint32 data [MONO_FILE_SIZE];
3017 for (i = 0; i < table->rows; ++i) {
3018 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3020 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3021 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3023 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3024 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3026 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3027 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3031 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3033 verify_exportedtype_table (VerifyContext *ctx)
3035 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3036 guint32 data [MONO_EXP_TYPE_SIZE];
3039 for (i = 0; i < table->rows; ++i) {
3040 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3042 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3043 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3045 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3046 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3048 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3049 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3051 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3052 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3054 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3055 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3057 /*nested type can't have a namespace*/
3058 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3059 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3063 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3065 verify_manifest_resource_table (VerifyContext *ctx)
3067 MonoCLIImageInfo *iinfo = ctx->image->image_info;
3068 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3069 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3070 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3073 resources_size = ch->ch_resources.size;
3075 for (i = 0; i < table->rows; ++i) {
3076 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3078 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3079 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3081 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3082 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3084 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3085 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3087 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3088 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3090 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3091 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3093 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3094 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token table %08x", i, get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION])));
3096 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3097 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3099 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3100 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3105 verify_nested_class_table (VerifyContext *ctx)
3107 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3108 guint32 data [MONO_NESTED_CLASS_SIZE];
3111 for (i = 0; i < table->rows; ++i) {
3112 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3114 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3115 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3116 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3117 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3118 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3119 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3123 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3125 verify_generic_param_table (VerifyContext *ctx)
3127 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3128 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3129 int i, param_number = 0;
3131 for (i = 0; i < table->rows; ++i) {
3132 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3134 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3135 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3137 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3138 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3140 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3141 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3143 token = data [MONO_GENERICPARAM_OWNER];
3145 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3146 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3148 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3149 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3151 if (token != last_token) {
3156 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3157 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d Number is out of order %d expected %d", i, data [MONO_GENERICPARAM_NUMBER], param_number));
3164 verify_method_spec_table (VerifyContext *ctx)
3166 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3167 guint32 data [MONO_METHODSPEC_SIZE];
3170 for (i = 0; i < table->rows; ++i) {
3171 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3173 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3174 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3176 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3177 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3179 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3180 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3185 verify_method_spec_table_full (VerifyContext *ctx)
3187 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3188 guint32 data [MONO_METHODSPEC_SIZE];
3191 for (i = 0; i < table->rows; ++i) {
3192 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3194 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3195 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3200 verify_generic_param_constraint_table (VerifyContext *ctx)
3202 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3203 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3206 for (i = 0; i < table->rows; ++i) {
3207 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3209 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3210 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3212 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3213 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3215 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3216 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3221 verify_tables_data (VerifyContext *ctx)
3223 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3224 guint32 size = 0, tables_offset;
3227 for (i = 0; i < 0x2D; ++i) {
3228 MonoTableInfo *table = &ctx->image->tables [i];
3230 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3231 if (tmp_size < size) {
3239 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3241 tables_offset = ctx->image->tables_base - ctx->data;
3242 if (!bounds_check_offset (&tables_area, tables_offset, size))
3243 ADD_ERROR (ctx, g_strdup_printf ("Tables data require %d bytes but the only %d are available in the #~ stream", size, tables_area.size - (tables_offset - tables_area.offset)));
3245 verify_module_table (ctx);
3247 verify_typeref_table (ctx);
3249 verify_typedef_table (ctx);
3251 verify_field_table (ctx);
3253 verify_method_table (ctx);
3255 verify_param_table (ctx);
3257 verify_interfaceimpl_table (ctx);
3259 verify_memberref_table (ctx);
3261 verify_constant_table (ctx);
3263 verify_cattr_table (ctx);
3265 verify_field_marshal_table (ctx);
3267 verify_decl_security_table (ctx);
3269 verify_class_layout_table (ctx);
3271 verify_field_layout_table (ctx);
3273 verify_standalonesig_table (ctx);
3275 verify_eventmap_table (ctx);
3277 verify_event_table (ctx);
3279 verify_propertymap_table (ctx);
3281 verify_property_table (ctx);
3283 verify_methodimpl_table (ctx);
3285 verify_moduleref_table (ctx);
3287 verify_typespec_table (ctx);
3289 verify_implmap_table (ctx);
3291 verify_fieldrva_table (ctx);
3293 verify_assembly_table (ctx);
3295 verify_assemblyref_table (ctx);
3297 verify_file_table (ctx);
3299 verify_exportedtype_table (ctx);
3301 verify_manifest_resource_table (ctx);
3303 verify_nested_class_table (ctx);
3305 verify_generic_param_table (ctx);
3307 verify_method_spec_table (ctx);
3309 verify_generic_param_constraint_table (ctx);
3313 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
3315 memset (ctx, 0, sizeof (VerifyContext));
3317 ctx->report_error = error_list != NULL;
3318 ctx->report_warning = FALSE; //export this setting in the API
3320 ctx->size = image->raw_data_len;
3321 ctx->data = image->raw_data;
3325 cleanup_context (VerifyContext *ctx, GSList **error_list)
3327 g_free (ctx->sections);
3329 *error_list = ctx->errors;
3331 mono_free_verify_list (ctx->errors);
3336 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3340 if (!mono_verifier_is_enabled_for_image (image))
3343 init_verify_context (&ctx, image, error_list);
3344 ctx.stage = STAGE_PE;
3346 verify_msdos_header (&ctx);
3348 verify_pe_header (&ctx);
3350 verify_pe_optional_header (&ctx);
3352 load_section_table (&ctx);
3354 load_data_directories (&ctx);
3356 verify_import_table (&ctx);
3358 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3359 verify_resources_table (&ctx);
3362 return cleanup_context (&ctx, error_list);
3366 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3370 if (!mono_verifier_is_enabled_for_image (image))
3373 init_verify_context (&ctx, image, error_list);
3374 ctx.stage = STAGE_CLI;
3376 verify_cli_header (&ctx);
3378 verify_metadata_header (&ctx);
3380 verify_tables_schema (&ctx);
3383 return cleanup_context (&ctx, error_list);
3388 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3389 * Other verification checks are meant to be done lazily by the runtime. Those include:
3390 * blob items (signatures, method headers, custom attributes, etc)
3391 * type semantics related
3393 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3395 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3396 * operation still need more checking.
3399 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3403 if (!mono_verifier_is_enabled_for_image (image))
3406 init_verify_context (&ctx, image, error_list);
3407 ctx.stage = STAGE_TABLES;
3409 verify_tables_data (&ctx);
3411 return cleanup_context (&ctx, error_list);
3416 * Verifies all other constraints.
3419 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3423 if (!mono_verifier_is_enabled_for_image (image))
3426 init_verify_context (&ctx, image, error_list);
3427 ctx.stage = STAGE_TABLES;
3429 verify_typedef_table_full (&ctx);
3431 verify_field_table_full (&ctx);
3433 verify_method_table_full (&ctx);
3435 verify_memberref_table_full (&ctx);
3437 verify_cattr_table_full (&ctx);
3439 verify_field_marshal_table_full (&ctx);
3441 verify_decl_security_table_full (&ctx);
3443 verify_standalonesig_table_full (&ctx);
3445 verify_event_table_full (&ctx);
3447 verify_typespec_table_full (&ctx);
3449 verify_method_spec_table_full (&ctx);
3452 return cleanup_context (&ctx, error_list);
3456 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3460 if (!mono_verifier_is_enabled_for_image (image))
3463 init_verify_context (&ctx, image, error_list);
3464 ctx.stage = STAGE_TABLES;
3466 is_valid_field_signature (&ctx, offset);
3467 return cleanup_context (&ctx, error_list);
3471 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3475 if (!mono_verifier_is_enabled_for_image (image))
3478 init_verify_context (&ctx, image, error_list);
3479 ctx.stage = STAGE_TABLES;
3481 is_valid_method_header (&ctx, offset);
3482 return cleanup_context (&ctx, error_list);
3486 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3490 if (!mono_verifier_is_enabled_for_image (image))
3493 init_verify_context (&ctx, image, error_list);
3494 ctx.stage = STAGE_TABLES;
3496 is_valid_method_signature (&ctx, offset);
3497 return cleanup_context (&ctx, error_list);
3501 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3505 if (!mono_verifier_is_enabled_for_image (image))
3508 init_verify_context (&ctx, image, error_list);
3509 ctx.stage = STAGE_TABLES;
3511 is_valid_method_or_field_signature (&ctx, offset);
3512 return cleanup_context (&ctx, error_list);
3516 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3520 if (!mono_verifier_is_enabled_for_image (image))
3523 init_verify_context (&ctx, image, error_list);
3524 ctx.stage = STAGE_TABLES;
3526 is_valid_standalonesig_blob (&ctx, offset);
3527 return cleanup_context (&ctx, error_list);
3531 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3535 if (!mono_verifier_is_enabled_for_image (image))
3538 init_verify_context (&ctx, image, error_list);
3539 ctx.stage = STAGE_TABLES;
3541 is_valid_typespec_blob (&ctx, offset);
3542 return cleanup_context (&ctx, error_list);
3546 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3550 if (!mono_verifier_is_enabled_for_image (image))
3553 init_verify_context (&ctx, image, error_list);
3554 ctx.stage = STAGE_TABLES;
3556 is_valid_methodspec_blog (&ctx, offset);
3557 return cleanup_context (&ctx, error_list);
3562 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3568 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3574 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3580 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3586 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3592 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3598 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3604 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3610 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3616 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3622 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3627 #endif /* DISABLE_VERIFIER */