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_NO_RETURN(__ctx, __msg) \
255 if ((__ctx)->report_error) \
256 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
257 (__ctx)->valid = 0; \
260 #define ADD_ERROR(__ctx, __msg) \
262 if ((__ctx)->report_error) \
263 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
264 (__ctx)->valid = 0; \
268 #define FAIL(__ctx, __msg) \
270 if ((__ctx)->report_error) \
271 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
272 (__ctx)->valid = 0; \
276 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
278 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
280 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
281 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
283 #if SIZEOF_VOID_P == 4
284 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
286 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
289 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
290 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
293 dword_align (const char *ptr)
295 #if SIZEOF_VOID_P == 8
296 return (const char *) (((guint64) (ptr + 3)) & ~3);
298 return (const char *) (((guint32) (ptr + 3)) & ~3);
303 pe_signature_offset (VerifyContext *ctx)
305 return read32 (ctx->data + 0x3c);
309 pe_header_offset (VerifyContext *ctx)
311 return read32 (ctx->data + 0x3c) + 4;
315 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
319 if (rva + size < rva) //overflow
322 if (ctx->stage > STAGE_PE) {
323 MonoCLIImageInfo *iinfo = ctx->image->image_info;
324 const int top = iinfo->cli_section_count;
325 MonoSectionTable *tables = iinfo->cli_section_tables;
328 for (i = 0; i < top; i++) {
329 guint32 base = tables->st_virtual_address;
330 guint32 end = base + tables->st_raw_data_size;
332 if (rva >= base && rva + size <= end)
335 /*if ((addr >= tables->st_virtual_address) &&
336 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
338 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
348 for (i = 0; i < ctx->section_count; ++i) {
349 guint32 base = ctx->sections [i].baseRVA;
350 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
351 if (rva >= base && rva + size <= end)
358 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
360 if (dir->translated_offset > offset)
362 if (dir->size < size)
364 return offset + size <= dir->translated_offset + dir->size;
368 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
370 if (off->offset > offset)
373 if (off->size < size)
376 return offset + size <= off->offset + off->size;
380 translate_rva (VerifyContext *ctx, guint32 rva)
384 if (ctx->stage > STAGE_PE)
385 return mono_cli_rva_image_map (ctx->image, rva);
390 for (i = 0; i < ctx->section_count; ++i) {
391 guint32 base = ctx->sections [i].baseRVA;
392 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
393 if (rva >= base && rva <= end) {
394 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
396 return res >= ctx->size ? INVALID_OFFSET : res;
400 return INVALID_OFFSET;
404 verify_msdos_header (VerifyContext *ctx)
408 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
409 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
410 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
411 lfanew = pe_signature_offset (ctx);
412 if (lfanew > ctx->size - 4)
413 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
417 verify_pe_header (VerifyContext *ctx)
419 guint32 offset = pe_signature_offset (ctx);
420 const char *pe_header = ctx->data + offset;
421 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
422 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
426 if (offset > ctx->size - 20)
427 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
428 if (read16 (pe_header) != 0x14c)
429 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
433 verify_pe_optional_header (VerifyContext *ctx)
435 guint32 offset = pe_header_offset (ctx);
436 guint32 header_size, file_alignment;
437 const char *pe_header = ctx->data + offset;
438 const char *pe_optional_header = pe_header + 20;
440 header_size = read16 (pe_header + 16);
443 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
444 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
446 if (offset > ctx->size - header_size || header_size > ctx->size)
447 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
449 if (read16 (pe_optional_header) == 0x10b) {
450 if (header_size != 224)
451 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
453 /* LAMESPEC MS plays around this value and ignore it during validation
454 if (read32 (pe_optional_header + 28) != 0x400000)
455 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
456 if (read32 (pe_optional_header + 32) != 0x2000)
457 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
458 file_alignment = read32 (pe_optional_header + 36);
459 if (file_alignment != 0x200 && file_alignment != 0x1000)
460 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
461 /* All the junk in the middle is irrelevant, specially for mono. */
462 if (read32 (pe_optional_header + 92) > 0x10)
463 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
465 if (read16 (pe_optional_header) == 0x20B)
466 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
468 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
473 load_section_table (VerifyContext *ctx)
476 SectionHeader *sections;
477 guint32 offset = pe_header_offset (ctx);
478 const char *ptr = ctx->data + offset;
479 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
481 offset += 244;/*FIXME, this constant is different under PE32+*/
484 if (num_sections * 40 > ctx->size - offset)
485 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
487 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
488 for (i = 0; i < num_sections; ++i) {
489 sections [i].size = read32 (ptr + 8);
490 sections [i].baseRVA = read32 (ptr + 12);
491 sections [i].baseOffset = read32 (ptr + 20);
492 sections [i].rellocationsRVA = read32 (ptr + 24);
493 sections [i].numberOfRelocations = read16 (ptr + 32);
497 ptr = ctx->data + offset; /*reset it to the beggining*/
498 for (i = 0; i < num_sections; ++i) {
499 guint32 raw_size, flags;
500 if (sections [i].baseOffset == 0)
501 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
502 if (sections [i].baseOffset >= ctx->size)
503 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
504 if (sections [i].size > ctx->size - sections [i].baseOffset)
505 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
507 raw_size = read32 (ptr + 16);
508 if (raw_size < sections [i].size)
509 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
511 if (raw_size > ctx->size - sections [i].baseOffset)
512 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
514 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
515 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
517 flags = read32 (ptr + 36);
518 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
519 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
520 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
527 is_valid_data_directory (int i)
529 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
530 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
534 load_data_directories (VerifyContext *ctx)
536 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
537 const char *ptr = ctx->data + offset;
540 for (i = 0; i < 16; ++i) {
541 guint32 rva = read32 (ptr);
542 guint32 size = read32 (ptr + 4);
544 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
545 if (i == CERTIFICATE_TABLE_IDX) {
549 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
550 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
552 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
553 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
555 ctx->data_directories [i].rva = rva;
556 ctx->data_directories [i].size = size;
557 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
563 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
565 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
568 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
571 guint32 hint_table_rva;
573 import_rva = translate_rva (ctx, import_rva);
574 g_assert (import_rva != INVALID_OFFSET);
576 hint_table_rva = read32 (ctx->data + import_rva);
577 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
578 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
580 hint_table_rva = translate_rva (ctx, hint_table_rva);
581 g_assert (hint_table_rva != INVALID_OFFSET);
582 ptr = ctx->data + hint_table_rva + 2;
584 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
585 char name[SIZE_OF_CORMAIN];
586 memcpy (name, ptr, SIZE_OF_CORMAIN);
587 name [SIZE_OF_CORMAIN - 1] = 0;
588 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
593 verify_import_table (VerifyContext *ctx)
595 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
596 guint32 offset = it.translated_offset;
597 const char *ptr = ctx->data + offset;
598 guint32 name_rva, ilt_rva, iat_rva;
600 g_assert (offset != INVALID_OFFSET);
603 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
605 ilt_rva = read32 (ptr);
606 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
607 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
609 name_rva = read32 (ptr + 12);
610 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
611 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
613 iat_rva = read32 (ptr + 16);
615 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
616 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
618 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
619 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));
623 name_rva = translate_rva (ctx, name_rva);
624 g_assert (name_rva != INVALID_OFFSET);
625 ptr = ctx->data + name_rva;
627 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
628 char name[SIZE_OF_MSCOREE];
629 memcpy (name, ptr, SIZE_OF_MSCOREE);
630 name [SIZE_OF_MSCOREE - 1] = 0;
631 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
636 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
641 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
645 verify_resources_table (VerifyContext *ctx)
647 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
649 guint16 named_entries, id_entries;
650 const char *ptr, *root, *end;
656 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));
658 offset = it.translated_offset;
659 root = ptr = ctx->data + offset;
660 end = root + it.size;
662 g_assert (offset != INVALID_OFFSET);
664 named_entries = read16 (ptr + 12);
665 id_entries = read16 (ptr + 14);
667 if ((named_entries + id_entries) * 8 + 16 > it.size)
668 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));
670 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
671 if (named_entries || id_entries)
672 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
676 /*----------nothing from here on can use data_directory---*/
679 get_data_dir (VerifyContext *ctx, int idx)
681 MonoCLIImageInfo *iinfo = ctx->image->image_info;
682 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
686 res.rva = entry->rva;
687 res.size = entry->size;
688 res.translated_offset = translate_rva (ctx, res.rva);
693 verify_cli_header (VerifyContext *ctx)
695 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
701 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
704 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
706 offset = it.translated_offset;
707 ptr = ctx->data + offset;
709 g_assert (offset != INVALID_OFFSET);
711 if (read16 (ptr) != 72)
712 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
714 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
715 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
718 if (!read32 (ptr + 8) || !read32 (ptr + 12))
719 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
721 if ((read32 (ptr + 16) & ~0x0001000B) != 0)
722 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
725 for (i = 0; i < 6; ++i) {
726 guint32 rva = read32 (ptr);
727 guint32 size = read32 (ptr + 4);
729 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
730 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
735 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
740 pad4 (guint32 offset)
742 if (offset & 0x3) //pad to the next 4 byte boundary
743 offset = (offset & ~0x3) + 4;
748 verify_metadata_header (VerifyContext *ctx)
751 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
752 guint32 offset, section_count;
755 offset = it.translated_offset;
756 ptr = ctx->data + offset;
757 g_assert (offset != INVALID_OFFSET);
759 //build a directory entry for the metadata root
761 it.rva = read32 (ptr);
763 it.size = read32 (ptr);
764 it.translated_offset = offset = translate_rva (ctx, it.rva);
766 ptr = ctx->data + offset;
767 g_assert (offset != INVALID_OFFSET);
770 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
772 if (read32 (ptr) != 0x424A5342)
773 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
775 offset = pad4 (offset + 16 + read32 (ptr + 12));
777 if (!bounds_check_datadir (&it, offset, 4))
778 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));
780 ptr = ctx->data + offset; //move to streams header
782 section_count = read16 (ptr + 2);
783 if (section_count < 3)
784 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob"));
789 for (i = 0; i < section_count; ++i) {
790 guint32 stream_off, stream_size;
791 int string_size, stream_idx;
793 if (!bounds_check_datadir (&it, offset, 8))
794 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));
796 stream_off = it.translated_offset + read32 (ptr);
797 stream_size = read32 (ptr + 4);
799 if (!bounds_check_datadir (&it, stream_off, stream_size))
800 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
805 for (string_size = 0; string_size < 32; ++string_size) {
806 if (!bounds_check_datadir (&it, offset++, 1))
807 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
808 if (!ptr [string_size])
812 if (ptr [string_size])
813 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
815 if (!strncmp ("#Strings", ptr, 9))
816 stream_idx = STRINGS_STREAM;
817 else if (!strncmp ("#US", ptr, 4))
818 stream_idx = USER_STRINGS_STREAM;
819 else if (!strncmp ("#Blob", ptr, 6))
820 stream_idx = BLOB_STREAM;
821 else if (!strncmp ("#GUID", ptr, 6))
822 stream_idx = GUID_STREAM;
823 else if (!strncmp ("#~", ptr, 3))
824 stream_idx = TILDE_STREAM;
826 ADD_WARNING (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
827 offset = pad4 (offset);
828 ptr = ctx->data + offset;
832 if (ctx->metadata_streams [stream_idx].offset != 0)
833 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
835 ctx->metadata_streams [stream_idx].offset = stream_off;
836 ctx->metadata_streams [stream_idx].size = stream_size;
838 offset = pad4 (offset);
839 ptr = ctx->data + offset;
842 if (!ctx->metadata_streams [TILDE_STREAM].size)
843 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
844 if (!ctx->metadata_streams [GUID_STREAM].size)
845 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
846 if (!ctx->metadata_streams [BLOB_STREAM].size)
847 ADD_ERROR (ctx, g_strdup_printf ("Metadata blob stream missing"));
852 verify_tables_schema (VerifyContext *ctx)
854 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
855 unsigned offset = tables_area.offset;
856 const char *ptr = ctx->data + offset;
857 guint64 valid_tables;
861 //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
862 if (tables_area.size < 24)
863 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
865 //printf ("ptr %x %x\n", ptr[4], ptr[5]);
866 if (ptr [4] != 2 && ptr [4] != 1)
867 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
869 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
871 if ((ptr [6] & ~0x7) != 0)
872 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]));
874 valid_tables = read64 (ptr + 8);
876 for (i = 0; i < 64; ++i) {
877 if (!(valid_tables & ((guint64)1 << i)))
880 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
881 Unused: 0x1E 0x1F 0x2D-0x3F
882 We don't care about the MS extensions.*/
883 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
884 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i));
885 if (i == 0x1E || i == 0x1F || i >= 0x2D)
886 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
890 if (tables_area.size < 24 + count * 4)
891 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));
894 for (i = 0; i < 64; ++i) {
895 if (valid_tables & ((guint64)1 << i)) {
896 guint32 row_count = read32 (ptr);
897 if (row_count > (1 << 24) - 1)
898 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
904 /*----------nothing from here on can use data_directory or metadata_streams ---*/
907 get_col_offset (VerifyContext *ctx, int table, int column)
909 guint32 bitfield = ctx->image->tables [table].size_bitfield;
913 offset += mono_metadata_table_size (bitfield, column);
919 get_col_size (VerifyContext *ctx, int table, int column)
921 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
925 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
928 res.offset = header->data - ctx->data;
929 res.size = header->size;
935 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
937 OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
939 const char *data = ctx->data + strings.offset;
941 if (offset >= strings.size)
943 if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing
946 if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
948 return allow_empty || length > 0;
952 is_valid_string (VerifyContext *ctx, guint32 offset)
954 return is_valid_string_full (ctx, offset, TRUE);
958 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
960 return is_valid_string_full (ctx, offset, FALSE);
964 is_valid_guid (VerifyContext *ctx, guint32 offset)
966 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
967 return guids.size >= 8 && guids.size - 8 >= offset;
971 get_coded_index_token (int token_kind, guint32 coded_token)
973 guint32 bits = coded_index_desc [token_kind];
974 return coded_token >> bits;
978 get_coded_index_table (int kind, guint32 coded_token)
980 guint32 idx, bits = coded_index_desc [kind];
982 idx = coded_token & ((1 << bits) - 1);
983 return coded_index_desc [kind + idx];
987 make_coded_token (int kind, guint32 table, guint32 table_idx)
989 guint32 bits = coded_index_desc [kind++];
990 guint32 tables = coded_index_desc [kind++];
992 for (i = 0; i < tables; ++i) {
993 if (coded_index_desc [kind++] == table)
994 return ((table_idx + 1) << bits) | i;
996 g_assert_not_reached ();
1001 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
1003 guint32 bits = coded_index_desc [token_kind++];
1004 guint32 table_count = coded_index_desc [token_kind++];
1005 guint32 table = coded_token & ((1 << bits) - 1);
1006 guint32 token = coded_token >> bits;
1008 if (table >= table_count)
1011 /*token_kind points to the first table idx*/
1012 table = coded_index_desc [token_kind + table];
1014 if (table == INVALID_TABLE)
1016 return token <= ctx->image->tables [table].rows;
1023 MonoTableInfo *table;
1027 token_locator (const void *a, const void *b)
1029 RowLocator *loc = (RowLocator *)a;
1030 unsigned const char *row = (unsigned const char *)b;
1031 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1033 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1034 return (int)loc->token - (int)token;
1038 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1040 MonoTableInfo *tinfo = &ctx->image->tables [table];
1042 const char *res, *base;
1043 locator.token = coded_token;
1044 locator.col_offset = get_col_offset (ctx, table, column);
1045 locator.col_size = get_col_size (ctx, table, column);
1046 locator.table = tinfo;
1050 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) );
1051 res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1055 return (res - base) / tinfo->row_size;
1058 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1060 get_string_ptr (VerifyContext *ctx, guint offset)
1062 return ctx->image->heap_strings.data + offset;
1065 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1067 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1070 return strcmp (str, "");
1072 return strcmp (str, get_string_ptr (ctx, offset));
1076 mono_verifier_is_corlib (MonoImage *image)
1078 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
1079 TRUE : mono_security_core_clr_is_platform_image (image);
1081 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1085 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1087 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1091 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1094 const unsigned char *ptr = (const unsigned char *)_ptr;
1102 if ((b & 0x80) == 0) {
1105 } else if ((b & 0x40) == 0) {
1109 *value = ((b & 0x3f) << 8 | ptr [1]);
1114 *value = ((b & 0x1f) << 24) |
1124 decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
1126 MonoStreamHeader blob = ctx->image->heap_blob;
1127 guint32 value, enc_size;
1129 if (offset >= blob.size)
1132 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1135 if (offset + enc_size + value < offset)
1138 if (offset + enc_size + value > blob.size)
1142 *first_byte = blob.data + offset + enc_size;
1147 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1149 const char *ptr = *_ptr;
1150 if (ptr + size > limit)
1154 *dest = *((guint8*)ptr);
1158 *dest = read16 (ptr);
1162 *dest = read32 (ptr);
1171 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1174 const char *ptr = *_ptr;
1175 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1180 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1181 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1182 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1183 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1186 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1189 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1192 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1194 const char *ptr = *_ptr;
1199 if (!safe_read8 (type, ptr, end))
1200 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1202 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1207 if (!safe_read_cint (token, ptr, end))
1208 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1210 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1211 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1219 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1221 const char *ptr = *_ptr;
1223 unsigned size, num, i;
1225 if (!safe_read8 (val, ptr, end))
1226 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1229 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1231 if (!safe_read_cint (size, ptr, end))
1232 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1234 for (i = 0; i < size; ++i) {
1235 if (!safe_read_cint (num, ptr, end))
1236 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1239 if (!safe_read_cint (size, ptr, end))
1240 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1242 for (i = 0; i < size; ++i) {
1243 if (!safe_read_cint (num, ptr, end))
1244 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1252 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1254 const char *ptr = *_ptr;
1256 unsigned count, token, i;
1258 if (!safe_read8 (type, ptr, end))
1259 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1261 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1262 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1264 if (!safe_read_cint (token, ptr, end))
1265 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1267 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1268 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1270 if (!safe_read_cint (count, ptr, end))
1271 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1274 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1276 for (i = 0; i < count; ++i) {
1277 if (!parse_type (ctx, &ptr, end))
1278 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1285 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1287 const char *ptr = *_ptr;
1291 if (!safe_read8 (type, ptr, end))
1292 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1294 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1295 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1296 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1297 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1298 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1302 if (!parse_custom_mods (ctx, &ptr, end))
1303 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1305 if (!safe_read8 (type, ptr, end))
1306 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1308 if (type != MONO_TYPE_VOID) {
1310 if (!parse_type (ctx, &ptr, end))
1311 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1315 case MONO_TYPE_VALUETYPE:
1316 case MONO_TYPE_CLASS:
1317 if (!safe_read_cint (token, ptr, end))
1318 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1320 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1321 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1325 case MONO_TYPE_MVAR:
1326 if (!safe_read_cint (token, ptr, end))
1327 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1330 case MONO_TYPE_ARRAY:
1331 if (!parse_type (ctx, &ptr, end))
1332 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1333 if (!parse_array_shape (ctx, &ptr, end))
1334 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1337 case MONO_TYPE_GENERICINST:
1338 if (!parse_generic_inst (ctx, &ptr, end))
1339 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1342 case MONO_TYPE_FNPTR:
1343 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1344 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1347 case MONO_TYPE_SZARRAY:
1348 if (!parse_custom_mods (ctx, &ptr, end))
1349 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1350 if (!parse_type (ctx, &ptr, end))
1351 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1359 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1364 if (!parse_custom_mods (ctx, _ptr, end))
1368 if (!safe_read8 (type, ptr, end))
1369 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1371 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1376 //it's a byref, update the cursor ptr
1377 if (type == MONO_TYPE_BYREF)
1380 return parse_type (ctx, _ptr, end);
1384 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1389 if (!parse_custom_mods (ctx, _ptr, end))
1393 if (!safe_read8 (type, ptr, end))
1394 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1396 if (type == MONO_TYPE_TYPEDBYREF) {
1401 //it's a byref, update the cursor ptr
1402 if (type == MONO_TYPE_BYREF)
1405 return parse_type (ctx, _ptr, end);
1409 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1412 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1413 const char *ptr = *_ptr;
1414 gboolean saw_sentinel = FALSE;
1416 if (!safe_read8 (cconv, ptr, end))
1417 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1420 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1422 if (allow_unmanaged) {
1423 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1424 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1425 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1426 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1428 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1429 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1431 if ((cconv & 0x10) && gparam_count == 0)
1432 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1434 if (allow_unmanaged && (cconv & 0x10))
1435 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1437 if (!safe_read_cint (param_count, ptr, end))
1438 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1440 if (!parse_return_type (ctx, &ptr, end))
1441 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1443 for (i = 0; i < param_count; ++i) {
1444 if (allow_sentinel) {
1445 if (!safe_read8 (type, ptr, end))
1446 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1448 if (type == MONO_TYPE_SENTINEL) {
1449 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1450 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1453 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1455 saw_sentinel = TRUE;
1461 if (!parse_param (ctx, &ptr, end))
1462 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1470 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1473 unsigned param_count = 0, i;
1474 const char *ptr = *_ptr;
1476 if (!safe_read8 (sig, ptr, end))
1477 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1479 if (sig != 0x08 && sig != 0x28)
1480 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1482 if (!safe_read_cint (param_count, ptr, end))
1483 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1485 if (!parse_custom_mods (ctx, &ptr, end))
1488 if (!parse_type (ctx, &ptr, end))
1489 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1491 for (i = 0; i < param_count; ++i) {
1492 if (!parse_type (ctx, &ptr, end))
1493 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1501 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1503 const char *ptr = *_ptr;
1504 unsigned signature = 0;
1506 if (!safe_read8 (signature, ptr, end))
1507 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1509 if (signature != 0x06)
1510 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1512 if (!parse_custom_mods (ctx, &ptr, end))
1515 if (safe_read8 (signature, ptr, end)) {
1516 if (signature != MONO_TYPE_BYREF)
1521 return parse_type (ctx, _ptr, end);
1525 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1528 unsigned locals_count = 0, i;
1529 const char *ptr = *_ptr;
1531 if (!safe_read8 (sig, ptr, end))
1532 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1535 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1537 if (!safe_read_cint (locals_count, ptr, end))
1538 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1540 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1541 if (locals_count == 0)
1542 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1545 for (i = 0; i < locals_count; ++i) {
1546 if (!safe_read8 (sig, ptr, end))
1547 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1549 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1550 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1551 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1552 if (!safe_read8 (sig, ptr, end))
1553 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1556 if (sig == MONO_TYPE_BYREF) {
1557 if (!safe_read8 (sig, ptr, end))
1558 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1559 if (sig == MONO_TYPE_TYPEDBYREF)
1560 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1563 if (sig == MONO_TYPE_TYPEDBYREF)
1568 if (!parse_type (ctx, &ptr, end))
1569 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1577 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1580 unsigned signature = 0;
1581 const char *ptr = NULL, *end;
1583 if (!decode_signature_header (ctx, offset, &size, &ptr))
1584 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1587 if (!safe_read8 (signature, ptr, end))
1588 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1591 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1594 return parse_field (ctx, &ptr, end);
1598 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1601 const char *ptr = NULL, *end;
1603 if (!decode_signature_header (ctx, offset, &size, &ptr))
1604 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1607 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1611 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1614 unsigned signature = 0;
1615 const char *ptr = NULL, *end;
1617 if (!decode_signature_header (ctx, offset, &size, &ptr))
1618 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1621 if (!safe_read8 (signature, ptr, end))
1622 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1625 if (signature == 0x06)
1626 return parse_field (ctx, &ptr, end);
1628 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1632 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1635 unsigned prolog = 0;
1636 const char *ptr = NULL, *end;
1641 if (!decode_signature_header (ctx, offset, &size, &ptr))
1642 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1645 if (!safe_read16 (prolog, ptr, end))
1646 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1649 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1655 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1657 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1658 //TODO do proper verification
1659 return blob.size >= 1 && blob.size - 1 >= offset;
1663 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1665 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1666 //TODO do proper verification
1667 return blob.size >= 1 && blob.size - 1 >= offset;
1671 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1674 unsigned signature = 0;
1675 const char *ptr = NULL, *end;
1677 if (!decode_signature_header (ctx, offset, &size, &ptr))
1678 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1681 if (!safe_read8 (signature, ptr, end))
1682 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1685 if (signature == 0x07)
1686 return parse_locals_signature (ctx, &ptr, end);
1687 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1691 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1694 const char *ptr = NULL, *end;
1696 if (!decode_signature_header (ctx, offset, &size, &ptr))
1697 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
1700 return parse_property_signature (ctx, &ptr, end);
1704 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1707 const char *ptr = NULL, *end;
1711 if (!decode_signature_header (ctx, offset, &size, &ptr))
1712 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
1715 if (!parse_custom_mods (ctx, &ptr, end))
1718 if (!safe_read8 (type, ptr, end))
1719 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
1721 if (type == MONO_TYPE_BYREF) {
1722 if (!safe_read8 (type, ptr, end))
1723 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
1724 if (type == MONO_TYPE_TYPEDBYREF)
1725 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
1728 if (type == MONO_TYPE_TYPEDBYREF)
1732 return parse_type (ctx, &ptr, end);
1736 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
1739 const char *ptr = NULL, *end;
1741 unsigned count = 0, i;
1743 if (!decode_signature_header (ctx, offset, &size, &ptr))
1744 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
1747 if (!safe_read8 (type, ptr, end))
1748 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
1751 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
1753 if (!safe_read_cint (count, ptr, end))
1754 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
1757 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
1759 for (i = 0; i < count; ++i) {
1760 if (!parse_type (ctx, &ptr, end))
1761 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
1767 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
1769 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1770 guint32 entry_size, bytes;
1772 if (blob.size < offset)
1775 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1778 if (entry_size < minsize)
1781 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
1783 entry_size += bytes;
1785 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
1789 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1791 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1792 guint32 size, entry_size, bytes;
1794 if (blob.size < offset)
1795 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
1797 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1798 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
1800 if (type == MONO_TYPE_STRING) {
1801 //String is encoded as: compressed_int:len len *bytes
1804 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
1805 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
1811 case MONO_TYPE_BOOLEAN:
1816 case MONO_TYPE_CHAR:
1824 case MONO_TYPE_CLASS:
1834 g_assert_not_reached ();
1837 if (size != entry_size)
1838 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
1842 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
1843 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
1845 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
1846 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
1850 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
1851 //only 0x01, 0x40 and 0x80 are allowed
1852 #define SECTION_HEADER_INVALID_FLAGS 0x3E
1855 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1857 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
1858 unsigned header = 0;
1859 unsigned fat_header = 0, size = 0, max_stack;
1860 const char *ptr = NULL, *end;
1862 if (offset == INVALID_ADDRESS)
1863 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
1865 ptr = ctx->data + offset;
1866 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
1868 if (!safe_read8 (header, ptr, end))
1869 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
1871 switch (header & 0x3) {
1874 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
1877 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
1878 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
1883 if (!safe_read16 (fat_header, ptr, end))
1884 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
1886 size = (fat_header >> 12) & 0xF;
1888 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
1890 if (!safe_read16 (max_stack, ptr, end))
1891 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
1893 if (!safe_read32 (code_size, ptr, end))
1894 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
1896 if (!safe_read32 (local_vars_tok, ptr, end))
1897 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
1899 if (local_vars_tok) {
1900 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
1901 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
1902 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
1903 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
1906 if (fat_header & FAT_HEADER_INVALID_FLAGS)
1907 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
1909 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
1910 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
1912 if (!(fat_header & 0x08))
1918 unsigned section_header = 0, section_size = 0;
1921 ptr = dword_align (ptr);
1922 if (!safe_read32 (section_header, ptr, end))
1923 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
1925 if (section_header & SECTION_HEADER_INVALID_FLAGS)
1926 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
1928 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
1929 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
1931 if (section_size < 4)
1932 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
1934 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
1935 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
1937 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
1938 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
1940 LAMEIMPL: MS emits section_size without accounting for header size.
1941 Mono does as the spec says. section_size is header + section
1942 MS's peverify happily accepts both.
1944 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
1945 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)));
1947 /* only verify the class token is verified as the rest is done by the IL verifier*/
1948 for (i = 0; i < clauses; ++i) {
1949 unsigned flags = *(unsigned char*)ptr;
1950 unsigned class_token = 0;
1951 ptr += (is_fat ? 20 : 8);
1952 if (!safe_read32 (class_token, ptr, end))
1953 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
1954 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
1955 guint table = mono_metadata_token_table (class_token);
1956 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
1957 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
1958 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
1959 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
1964 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
1971 verify_module_table (VerifyContext *ctx)
1973 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1974 guint32 data [MONO_MODULE_SIZE];
1976 if (table->rows != 1)
1977 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1979 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1981 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1982 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1984 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1985 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1987 if (data [MONO_MODULE_ENC] != 0)
1988 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1990 if (data [MONO_MODULE_ENCBASE] != 0)
1991 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1995 verify_typeref_table (VerifyContext *ctx)
1997 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1998 guint32 data [MONO_TYPEREF_SIZE];
2001 for (i = 0; i < table->rows; ++i) {
2002 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
2003 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
2004 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
2006 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
2007 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
2009 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
2010 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
2012 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2013 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
2017 /*bits 9,11,14,15,19,21,24-31 */
2018 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2020 verify_typedef_table (VerifyContext *ctx)
2022 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2023 guint32 data [MONO_TYPEDEF_SIZE];
2024 guint32 fieldlist = 1, methodlist = 1, visibility;
2027 if (table->rows == 0)
2028 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2030 for (i = 0; i < table->rows; ++i) {
2031 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2032 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2033 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2035 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2036 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2038 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2039 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2041 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2042 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2044 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2045 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2047 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2048 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2050 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2051 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2053 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2054 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2056 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2057 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2058 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2059 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2061 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2062 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2064 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2065 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2067 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2068 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));
2070 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2071 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2073 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2074 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2076 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2077 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));
2079 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2080 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2085 verify_typedef_table_full (VerifyContext *ctx)
2087 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2088 guint32 data [MONO_TYPEDEF_SIZE];
2091 if (table->rows == 0)
2092 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2094 for (i = 0; i < table->rows; ++i) {
2095 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2098 if (data [MONO_TYPEDEF_EXTENDS] != 0)
2099 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2103 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2104 if (data [MONO_TYPEDEF_EXTENDS])
2105 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2107 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2108 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2112 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2115 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2123 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2125 verify_field_table (VerifyContext *ctx)
2127 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2128 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2131 module_field_list = (guint32)-1;
2132 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2133 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2134 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2137 for (i = 0; i < table->rows; ++i) {
2138 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2139 flags = data [MONO_FIELD_FLAGS];
2141 if (flags & INVALID_FIELD_FLAG_BITS)
2142 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2144 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2145 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2147 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2148 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2150 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2151 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2153 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2154 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2156 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2157 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2158 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2160 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2161 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2162 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2164 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2165 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2166 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2168 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2169 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2170 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2172 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2173 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2175 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2176 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2178 //TODO verify contant flag
2180 if (i + 1 < module_field_list) {
2181 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2182 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2183 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2184 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2185 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2191 verify_field_table_full (VerifyContext *ctx)
2193 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2194 guint32 data [MONO_FIELD_SIZE];
2197 for (i = 0; i < table->rows; ++i) {
2198 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2200 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2201 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2205 /*bits 6,8,9,10,11,13,14,15*/
2206 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2208 verify_method_table (VerifyContext *ctx)
2210 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2211 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2212 guint32 paramlist = 1;
2213 gboolean is_ctor, is_cctor;
2217 module_method_list = (guint32)-1;
2218 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2219 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2220 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2223 for (i = 0; i < table->rows; ++i) {
2224 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2225 rva = data [MONO_METHOD_RVA];
2226 implflags = data [MONO_METHOD_IMPLFLAGS];
2227 flags = data [MONO_METHOD_FLAGS];
2228 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2229 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2232 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2233 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2236 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2238 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2239 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2241 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2242 is_ctor = !strcmp (".ctor", name);
2243 is_cctor = !strcmp (".cctor", name);
2245 if ((is_ctor || is_cctor) &&
2246 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2247 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2249 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2250 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2252 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2253 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2254 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2255 if (flags & METHOD_ATTRIBUTE_FINAL)
2256 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2257 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2258 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2261 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2262 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2264 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2265 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2267 //XXX no checks against cas stuff 10,11,12,13)
2269 //TODO check iface with .ctor (15,16)
2271 if (i + 1 < module_method_list) {
2272 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2273 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2274 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2275 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2276 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2277 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2280 //TODO check valuetype for synchronized
2282 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2283 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2285 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2286 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2287 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2288 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2289 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2292 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2293 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2294 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2296 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2297 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2299 //TODO check signature contents
2302 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2303 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2304 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2305 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2307 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2308 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2311 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2313 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2314 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2315 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2317 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2318 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2320 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2321 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2323 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2324 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2326 if (data [MONO_METHOD_PARAMLIST] == 0)
2327 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2329 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2330 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));
2332 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2333 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2335 paramlist = data [MONO_METHOD_PARAMLIST];
2341 verify_method_table_full (VerifyContext *ctx)
2343 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2344 guint32 data [MONO_METHOD_SIZE], rva;
2347 for (i = 0; i < table->rows; ++i) {
2348 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2349 rva = data [MONO_METHOD_RVA];
2351 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2352 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2354 if (rva && !is_valid_method_header (ctx, rva))
2355 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2360 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2362 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2363 guint32 row = *current_method;
2364 guint32 paramlist, tmp;
2367 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2368 while (row < table->rows) {
2369 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2370 if (tmp > paramlist) {
2371 *current_method = row;
2372 return tmp - paramlist;
2377 /*no more methods, all params apply to the last one*/
2378 *current_method = table->rows;
2383 #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))
2385 verify_param_table (VerifyContext *ctx)
2387 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2388 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2389 gboolean first_param = TRUE;
2392 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2393 if (table->rows > 0)
2394 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2398 remaining_params = get_next_param_count (ctx, ¤t_method);
2400 for (i = 0; i < table->rows; ++i) {
2401 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2402 flags = data [MONO_PARAM_FLAGS];
2404 if (flags & INVALID_PARAM_FLAGS_BITS)
2405 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2407 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2408 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2409 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2411 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2412 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2415 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)
2416 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2418 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2419 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2421 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2422 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2424 first_param = FALSE;
2425 sequence = data [MONO_PARAM_SEQUENCE];
2426 if (--remaining_params == 0) {
2427 remaining_params = get_next_param_count (ctx, ¤t_method);
2434 verify_interfaceimpl_table (VerifyContext *ctx)
2436 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2437 guint32 data [MONO_INTERFACEIMPL_SIZE];
2440 for (i = 0; i < table->rows; ++i) {
2441 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2442 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2443 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2445 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2446 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2448 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2449 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2454 verify_memberref_table (VerifyContext *ctx)
2456 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2457 guint32 data [MONO_MEMBERREF_SIZE];
2460 for (i = 0; i < table->rows; ++i) {
2461 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2463 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2464 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2466 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2467 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2469 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2470 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2472 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2473 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2479 verify_memberref_table_full (VerifyContext *ctx)
2481 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2482 guint32 data [MONO_MEMBERREF_SIZE];
2485 for (i = 0; i < table->rows; ++i) {
2486 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2488 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2489 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2494 verify_constant_table (VerifyContext *ctx)
2496 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2497 guint32 data [MONO_CONSTANT_SIZE], type;
2500 for (i = 0; i < table->rows; ++i) {
2501 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2502 type = data [MONO_CONSTANT_TYPE];
2504 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2505 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2507 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2508 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2510 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2511 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2513 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2514 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2519 verify_cattr_table (VerifyContext *ctx)
2521 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2522 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2525 for (i = 0; i < table->rows; ++i) {
2526 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2528 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2529 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2531 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2532 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2534 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2535 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2540 verify_cattr_table_full (VerifyContext *ctx)
2542 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2543 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2546 for (i = 0; i < table->rows; ++i) {
2547 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2549 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2550 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2555 verify_field_marshal_table (VerifyContext *ctx)
2557 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2558 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2561 for (i = 0; i < table->rows; ++i) {
2562 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2564 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2565 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2567 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2568 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2570 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2571 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2573 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2574 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2579 verify_field_marshal_table_full (VerifyContext *ctx)
2581 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2582 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2585 for (i = 0; i < table->rows; ++i) {
2586 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2588 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2589 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2594 verify_decl_security_table (VerifyContext *ctx)
2596 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2597 guint32 data [MONO_DECL_SECURITY_SIZE];
2600 for (i = 0; i < table->rows; ++i) {
2601 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2603 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2604 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2606 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2607 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2609 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2610 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2615 verify_decl_security_table_full (VerifyContext *ctx)
2617 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2618 guint32 data [MONO_DECL_SECURITY_SIZE];
2621 for (i = 0; i < table->rows; ++i) {
2622 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2624 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2625 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2630 verify_class_layout_table (VerifyContext *ctx)
2632 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2633 guint32 data [MONO_CLASS_LAYOUT_SIZE];
2636 for (i = 0; i < table->rows; ++i) {
2637 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2639 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2640 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2642 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2654 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2660 verify_field_layout_table (VerifyContext *ctx)
2662 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2663 guint32 data [MONO_FIELD_LAYOUT_SIZE];
2666 for (i = 0; i < table->rows; ++i) {
2667 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2669 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2670 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2675 verify_standalonesig_table (VerifyContext *ctx)
2677 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2678 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2681 for (i = 0; i < table->rows; ++i) {
2682 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2684 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
2685 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2690 verify_standalonesig_table_full (VerifyContext *ctx)
2692 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2693 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2696 for (i = 0; i < table->rows; ++i) {
2697 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2699 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2700 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2705 verify_eventmap_table (VerifyContext *ctx)
2707 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2708 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2711 for (i = 0; i < table->rows; ++i) {
2712 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2714 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2715 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2717 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2718 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2720 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2724 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2726 verify_event_table (VerifyContext *ctx)
2728 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2729 guint32 data [MONO_EVENT_SIZE];
2732 for (i = 0; i < table->rows; ++i) {
2733 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2735 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2736 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2738 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2739 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2741 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2742 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2747 verify_event_table_full (VerifyContext *ctx)
2749 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2750 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2751 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2752 gboolean found_add, found_remove;
2755 for (i = 0; i < table->rows; ++i) {
2756 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2758 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2759 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2761 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2763 //first we move to the first row for this event
2765 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2769 //now move forward looking for AddOn and RemoveOn rows
2770 found_add = found_remove = FALSE;
2771 while (idx < sema_table->rows) {
2772 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2773 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2775 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2777 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2778 found_remove = TRUE;
2779 if (found_add && found_remove)
2785 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2787 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2792 verify_propertymap_table (VerifyContext *ctx)
2794 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2795 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2798 for (i = 0; i < table->rows; ++i) {
2799 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2801 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2802 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2804 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2805 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2807 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2811 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2813 verify_property_table (VerifyContext *ctx)
2815 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2816 guint32 data [MONO_PROPERTY_SIZE];
2819 for (i = 0; i < table->rows; ++i) {
2820 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2822 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2823 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2825 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2826 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2828 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2829 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2831 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2832 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2833 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2839 verify_methodimpl_table (VerifyContext *ctx)
2841 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2842 guint32 data [MONO_METHODIMPL_SIZE];
2845 for (i = 0; i < table->rows; ++i) {
2846 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2848 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2849 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2851 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2852 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2854 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2855 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2857 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2858 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2860 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2861 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2866 verify_moduleref_table (VerifyContext *ctx)
2868 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2869 guint32 data [MONO_MODULEREF_SIZE];
2872 for (i = 0; i < table->rows; ++i) {
2873 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2875 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2876 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2881 verify_typespec_table (VerifyContext *ctx)
2883 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2884 guint32 data [MONO_TYPESPEC_SIZE];
2887 for (i = 0; i < table->rows; ++i) {
2888 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2890 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
2891 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2896 verify_typespec_table_full (VerifyContext *ctx)
2898 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2899 guint32 data [MONO_TYPESPEC_SIZE];
2902 for (i = 0; i < table->rows; ++i) {
2903 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2905 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2906 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2910 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
2912 verify_implmap_table (VerifyContext *ctx)
2914 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2915 guint32 data [MONO_IMPLMAP_SIZE], cconv;
2918 for (i = 0; i < table->rows; ++i) {
2919 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2921 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2922 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2924 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2925 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2926 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2928 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2929 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2931 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2932 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2934 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2935 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2937 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2938 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2940 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
2941 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2946 verify_fieldrva_table (VerifyContext *ctx)
2948 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2949 guint32 data [MONO_FIELD_RVA_SIZE];
2952 for (i = 0; i < table->rows; ++i) {
2953 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2955 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2956 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2958 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2959 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2963 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
2965 verify_assembly_table (VerifyContext *ctx)
2967 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2968 guint32 data [MONO_ASSEMBLY_SIZE], hash;
2971 if (table->rows > 1)
2972 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2974 for (i = 0; i < table->rows; ++i) {
2975 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2977 hash = data [MONO_ASSEMBLY_HASH_ALG];
2978 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2979 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2981 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2982 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2984 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
2985 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2987 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2988 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2990 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2991 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2995 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2997 verify_assemblyref_table (VerifyContext *ctx)
2999 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3000 guint32 data [MONO_ASSEMBLYREF_SIZE];
3003 for (i = 0; i < table->rows; ++i) {
3004 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3006 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3007 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3009 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3010 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3012 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3013 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3015 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3016 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3018 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3019 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3023 #define INVALID_FILE_FLAGS_BITS ~(1)
3025 verify_file_table (VerifyContext *ctx)
3027 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3028 guint32 data [MONO_FILE_SIZE];
3031 for (i = 0; i < table->rows; ++i) {
3032 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3034 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3035 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3037 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3038 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3040 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3041 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3045 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3047 verify_exportedtype_table (VerifyContext *ctx)
3049 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3050 guint32 data [MONO_EXP_TYPE_SIZE];
3053 for (i = 0; i < table->rows; ++i) {
3054 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3056 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3057 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3059 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3060 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3062 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3063 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3065 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3066 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3068 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3069 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3071 /*nested type can't have a namespace*/
3072 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3073 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3077 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3079 verify_manifest_resource_table (VerifyContext *ctx)
3081 MonoCLIImageInfo *iinfo = ctx->image->image_info;
3082 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3083 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3084 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3087 resources_size = ch->ch_resources.size;
3089 for (i = 0; i < table->rows; ++i) {
3090 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3092 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3093 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3095 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3096 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3098 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3099 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3101 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3102 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3104 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3105 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3107 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3108 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])));
3110 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3111 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3113 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3114 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3119 verify_nested_class_table (VerifyContext *ctx)
3121 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3122 guint32 data [MONO_NESTED_CLASS_SIZE];
3125 for (i = 0; i < table->rows; ++i) {
3126 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3128 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3129 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3130 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3131 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3132 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3133 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3137 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3139 verify_generic_param_table (VerifyContext *ctx)
3141 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3142 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3143 int i, param_number = 0;
3145 for (i = 0; i < table->rows; ++i) {
3146 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3148 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3149 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3151 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3152 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3154 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3155 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3157 token = data [MONO_GENERICPARAM_OWNER];
3159 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3160 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3162 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3163 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3165 if (token != last_token) {
3170 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3171 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));
3178 verify_method_spec_table (VerifyContext *ctx)
3180 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3181 guint32 data [MONO_METHODSPEC_SIZE];
3184 for (i = 0; i < table->rows; ++i) {
3185 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3187 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3188 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3190 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3191 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3193 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3194 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3199 verify_method_spec_table_full (VerifyContext *ctx)
3201 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3202 guint32 data [MONO_METHODSPEC_SIZE];
3205 for (i = 0; i < table->rows; ++i) {
3206 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3208 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3209 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3214 verify_generic_param_constraint_table (VerifyContext *ctx)
3216 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3217 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3220 for (i = 0; i < table->rows; ++i) {
3221 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3223 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3224 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3226 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3227 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3229 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3230 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3237 const char *name_space;
3238 guint32 resolution_scope;
3242 typedef_hash (gconstpointer _key)
3244 const TypeDefUniqueId *key = _key;
3245 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3249 typedef_equals (gconstpointer _a, gconstpointer _b)
3251 const TypeDefUniqueId *a = _a;
3252 const TypeDefUniqueId *b = _b;
3253 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3257 verify_typedef_table_global_constraints (VerifyContext *ctx)
3260 guint32 data [MONO_TYPEDEF_SIZE];
3261 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3262 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3263 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3264 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3266 for (i = 0; i < table->rows; ++i) {
3268 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3269 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3271 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3272 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3273 type->resolution_scope = 0;
3275 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3276 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3277 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3278 g_assert (res >= 0);
3280 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3281 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3284 if (g_hash_table_lookup (unique_types, type)) {
3285 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("TypeDef table row %d has duplicate for tuple (%s,%s,%x)", i, type->name, type->name_space, type->resolution_scope));
3286 g_hash_table_destroy (unique_types);
3290 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3293 g_hash_table_destroy (unique_types);
3297 verify_typeref_table_global_constraints (VerifyContext *ctx)
3300 guint32 data [MONO_TYPEREF_SIZE];
3301 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3302 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3304 for (i = 0; i < table->rows; ++i) {
3305 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3306 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3308 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3309 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3310 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3312 if (g_hash_table_lookup (unique_types, type)) {
3313 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("TypeRef table row %d has duplicate for tuple (%s,%s,%x)", i, type->name, type->name_space, type->resolution_scope));
3314 g_hash_table_destroy (unique_types);
3318 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3321 g_hash_table_destroy (unique_types);
3325 verify_tables_data_global_constraints (VerifyContext *ctx)
3327 verify_typeref_table_global_constraints (ctx);
3329 verify_typedef_table_global_constraints (ctx);
3333 verify_tables_data (VerifyContext *ctx)
3335 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3336 guint32 size = 0, tables_offset;
3339 for (i = 0; i < 0x2D; ++i) {
3340 MonoTableInfo *table = &ctx->image->tables [i];
3342 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3343 if (tmp_size < size) {
3351 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3353 tables_offset = ctx->image->tables_base - ctx->data;
3354 if (!bounds_check_offset (&tables_area, tables_offset, size))
3355 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)));
3357 verify_module_table (ctx);
3359 verify_typeref_table (ctx);
3361 verify_typedef_table (ctx);
3363 verify_field_table (ctx);
3365 verify_method_table (ctx);
3367 verify_param_table (ctx);
3369 verify_interfaceimpl_table (ctx);
3371 verify_memberref_table (ctx);
3373 verify_constant_table (ctx);
3375 verify_cattr_table (ctx);
3377 verify_field_marshal_table (ctx);
3379 verify_decl_security_table (ctx);
3381 verify_class_layout_table (ctx);
3383 verify_field_layout_table (ctx);
3385 verify_standalonesig_table (ctx);
3387 verify_eventmap_table (ctx);
3389 verify_event_table (ctx);
3391 verify_propertymap_table (ctx);
3393 verify_property_table (ctx);
3395 verify_methodimpl_table (ctx);
3397 verify_moduleref_table (ctx);
3399 verify_typespec_table (ctx);
3401 verify_implmap_table (ctx);
3403 verify_fieldrva_table (ctx);
3405 verify_assembly_table (ctx);
3407 verify_assemblyref_table (ctx);
3409 verify_file_table (ctx);
3411 verify_exportedtype_table (ctx);
3413 verify_manifest_resource_table (ctx);
3415 verify_nested_class_table (ctx);
3417 verify_generic_param_table (ctx);
3419 verify_method_spec_table (ctx);
3421 verify_generic_param_constraint_table (ctx);
3423 verify_tables_data_global_constraints (ctx);
3427 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
3429 memset (ctx, 0, sizeof (VerifyContext));
3431 ctx->report_error = error_list != NULL;
3432 ctx->report_warning = FALSE; //export this setting in the API
3434 ctx->size = image->raw_data_len;
3435 ctx->data = image->raw_data;
3439 cleanup_context (VerifyContext *ctx, GSList **error_list)
3441 g_free (ctx->sections);
3443 *error_list = ctx->errors;
3445 mono_free_verify_list (ctx->errors);
3450 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3454 if (!mono_verifier_is_enabled_for_image (image))
3457 init_verify_context (&ctx, image, error_list);
3458 ctx.stage = STAGE_PE;
3460 verify_msdos_header (&ctx);
3462 verify_pe_header (&ctx);
3464 verify_pe_optional_header (&ctx);
3466 load_section_table (&ctx);
3468 load_data_directories (&ctx);
3470 verify_import_table (&ctx);
3472 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3473 verify_resources_table (&ctx);
3476 return cleanup_context (&ctx, error_list);
3480 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3484 if (!mono_verifier_is_enabled_for_image (image))
3487 init_verify_context (&ctx, image, error_list);
3488 ctx.stage = STAGE_CLI;
3490 verify_cli_header (&ctx);
3492 verify_metadata_header (&ctx);
3494 verify_tables_schema (&ctx);
3497 return cleanup_context (&ctx, error_list);
3502 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3503 * Other verification checks are meant to be done lazily by the runtime. Those include:
3504 * blob items (signatures, method headers, custom attributes, etc)
3505 * type semantics related
3507 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3509 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3510 * operation still need more checking.
3513 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3517 if (!mono_verifier_is_enabled_for_image (image))
3520 init_verify_context (&ctx, image, error_list);
3521 ctx.stage = STAGE_TABLES;
3523 verify_tables_data (&ctx);
3525 return cleanup_context (&ctx, error_list);
3530 * Verifies all other constraints.
3533 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3537 if (!mono_verifier_is_enabled_for_image (image))
3540 init_verify_context (&ctx, image, error_list);
3541 ctx.stage = STAGE_TABLES;
3543 verify_typedef_table_full (&ctx);
3545 verify_field_table_full (&ctx);
3547 verify_method_table_full (&ctx);
3549 verify_memberref_table_full (&ctx);
3551 verify_cattr_table_full (&ctx);
3553 verify_field_marshal_table_full (&ctx);
3555 verify_decl_security_table_full (&ctx);
3557 verify_standalonesig_table_full (&ctx);
3559 verify_event_table_full (&ctx);
3561 verify_typespec_table_full (&ctx);
3563 verify_method_spec_table_full (&ctx);
3566 return cleanup_context (&ctx, error_list);
3570 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3574 if (!mono_verifier_is_enabled_for_image (image))
3577 init_verify_context (&ctx, image, error_list);
3578 ctx.stage = STAGE_TABLES;
3580 is_valid_field_signature (&ctx, offset);
3581 return cleanup_context (&ctx, error_list);
3585 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3589 if (!mono_verifier_is_enabled_for_image (image))
3592 init_verify_context (&ctx, image, error_list);
3593 ctx.stage = STAGE_TABLES;
3595 is_valid_method_header (&ctx, offset);
3596 return cleanup_context (&ctx, error_list);
3600 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3604 if (!mono_verifier_is_enabled_for_image (image))
3607 init_verify_context (&ctx, image, error_list);
3608 ctx.stage = STAGE_TABLES;
3610 is_valid_method_signature (&ctx, offset);
3611 return cleanup_context (&ctx, error_list);
3615 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3619 if (!mono_verifier_is_enabled_for_image (image))
3622 init_verify_context (&ctx, image, error_list);
3623 ctx.stage = STAGE_TABLES;
3625 is_valid_method_or_field_signature (&ctx, offset);
3626 return cleanup_context (&ctx, error_list);
3630 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3634 if (!mono_verifier_is_enabled_for_image (image))
3637 init_verify_context (&ctx, image, error_list);
3638 ctx.stage = STAGE_TABLES;
3640 is_valid_standalonesig_blob (&ctx, offset);
3641 return cleanup_context (&ctx, error_list);
3645 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3649 if (!mono_verifier_is_enabled_for_image (image))
3652 init_verify_context (&ctx, image, error_list);
3653 ctx.stage = STAGE_TABLES;
3655 is_valid_typespec_blob (&ctx, offset);
3656 return cleanup_context (&ctx, error_list);
3660 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3664 if (!mono_verifier_is_enabled_for_image (image))
3667 init_verify_context (&ctx, image, error_list);
3668 ctx.stage = STAGE_TABLES;
3670 is_valid_methodspec_blob (&ctx, offset);
3671 return cleanup_context (&ctx, error_list);
3675 verify_user_string (VerifyContext *ctx, guint32 offset)
3677 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
3678 guint32 entry_size, bytes;
3680 if (heap_us.size < offset)
3681 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
3683 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
3684 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
3686 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
3687 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
3689 entry_size += bytes;
3691 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
3692 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
3696 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
3700 if (!mono_verifier_is_enabled_for_image (image))
3703 init_verify_context (&ctx, image, error_list);
3704 ctx.stage = STAGE_TABLES;
3706 verify_user_string (&ctx, offset);
3708 return cleanup_context (&ctx, error_list);
3712 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
3714 MonoMethodSignature *original_sig;
3715 if (!mono_verifier_is_enabled_for_image (image))
3718 original_sig = mono_method_signature (method);
3719 if (original_sig->call_convention == MONO_CALL_VARARG) {
3720 if (original_sig->hasthis != signature->hasthis)
3722 if (original_sig->call_convention != signature->call_convention)
3724 if (original_sig->explicit_this != signature->explicit_this)
3726 if (original_sig->call_convention != signature->call_convention)
3728 if (original_sig->pinvoke != signature->pinvoke)
3730 if (original_sig->sentinelpos != signature->sentinelpos)
3732 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
3741 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3747 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3753 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3759 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3765 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3771 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3777 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3783 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3789 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3795 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3801 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3807 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
3813 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
3819 #endif /* DISABLE_VERIFIER */