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 verifies 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_blog (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_VIRTUAL))
2256 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2259 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2260 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2262 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2263 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2265 //XXX no checks against cas stuff 10,11,12,13)
2267 //TODO check iface with .ctor (15,16)
2269 if (i + 1 < module_method_list) {
2270 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2271 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2272 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2273 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2274 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2275 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2278 //TODO check valuetype for synchronized
2280 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2281 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2283 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2284 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2285 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2286 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2287 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2290 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2291 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2292 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2294 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2295 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2297 //TODO check signature contents
2300 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2301 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2302 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2303 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2305 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2306 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2309 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2311 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2312 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2313 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2315 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2316 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2318 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2319 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2321 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2322 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2324 if (data [MONO_METHOD_PARAMLIST] == 0)
2325 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2327 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2328 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));
2330 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2331 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2333 paramlist = data [MONO_METHOD_PARAMLIST];
2339 verify_method_table_full (VerifyContext *ctx)
2341 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2342 guint32 data [MONO_METHOD_SIZE], rva;
2345 for (i = 0; i < table->rows; ++i) {
2346 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2347 rva = data [MONO_METHOD_RVA];
2349 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2350 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2352 if (rva && !is_valid_method_header (ctx, rva))
2353 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2358 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2360 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2361 guint32 row = *current_method;
2362 guint32 paramlist, tmp;
2365 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2366 while (row < table->rows) {
2367 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2368 if (tmp > paramlist) {
2369 *current_method = row;
2370 return tmp - paramlist;
2375 /*no more methods, all params apply to the last one*/
2376 *current_method = table->rows;
2381 #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))
2383 verify_param_table (VerifyContext *ctx)
2385 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2386 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2387 gboolean first_param = TRUE;
2390 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2391 if (table->rows > 0)
2392 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2396 remaining_params = get_next_param_count (ctx, ¤t_method);
2398 for (i = 0; i < table->rows; ++i) {
2399 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2400 flags = data [MONO_PARAM_FLAGS];
2402 if (flags & INVALID_PARAM_FLAGS_BITS)
2403 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2405 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2406 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2407 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2409 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2410 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2413 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)
2414 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2416 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2417 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2419 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2420 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2422 first_param = FALSE;
2423 sequence = data [MONO_PARAM_SEQUENCE];
2424 if (--remaining_params == 0) {
2425 remaining_params = get_next_param_count (ctx, ¤t_method);
2432 verify_interfaceimpl_table (VerifyContext *ctx)
2434 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2435 guint32 data [MONO_INTERFACEIMPL_SIZE];
2438 for (i = 0; i < table->rows; ++i) {
2439 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2440 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2441 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2443 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2444 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2446 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2447 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2452 verify_memberref_table (VerifyContext *ctx)
2454 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2455 guint32 data [MONO_MEMBERREF_SIZE];
2458 for (i = 0; i < table->rows; ++i) {
2459 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2461 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2462 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2464 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2465 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2467 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2468 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2470 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2471 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2477 verify_memberref_table_full (VerifyContext *ctx)
2479 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2480 guint32 data [MONO_MEMBERREF_SIZE];
2483 for (i = 0; i < table->rows; ++i) {
2484 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2486 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2487 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2492 verify_constant_table (VerifyContext *ctx)
2494 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2495 guint32 data [MONO_CONSTANT_SIZE], type;
2498 for (i = 0; i < table->rows; ++i) {
2499 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2500 type = data [MONO_CONSTANT_TYPE];
2502 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2503 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2505 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2506 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2508 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2509 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2511 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2512 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2517 verify_cattr_table (VerifyContext *ctx)
2519 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2520 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2523 for (i = 0; i < table->rows; ++i) {
2524 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2526 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2527 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2529 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2530 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2532 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2533 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2538 verify_cattr_table_full (VerifyContext *ctx)
2540 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2541 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2544 for (i = 0; i < table->rows; ++i) {
2545 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2547 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2548 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2553 verify_field_marshal_table (VerifyContext *ctx)
2555 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2556 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2559 for (i = 0; i < table->rows; ++i) {
2560 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2562 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2563 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2565 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2566 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2568 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2569 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2571 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2572 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2577 verify_field_marshal_table_full (VerifyContext *ctx)
2579 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2580 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2583 for (i = 0; i < table->rows; ++i) {
2584 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2586 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2587 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2592 verify_decl_security_table (VerifyContext *ctx)
2594 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2595 guint32 data [MONO_DECL_SECURITY_SIZE];
2598 for (i = 0; i < table->rows; ++i) {
2599 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2601 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2602 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2604 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2605 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2607 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2608 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2613 verify_decl_security_table_full (VerifyContext *ctx)
2615 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2616 guint32 data [MONO_DECL_SECURITY_SIZE];
2619 for (i = 0; i < table->rows; ++i) {
2620 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2622 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2623 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2628 verify_class_layout_table (VerifyContext *ctx)
2630 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2631 guint32 data [MONO_CLASS_LAYOUT_SIZE];
2634 for (i = 0; i < table->rows; ++i) {
2635 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2637 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2638 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2640 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2652 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2658 verify_field_layout_table (VerifyContext *ctx)
2660 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2661 guint32 data [MONO_FIELD_LAYOUT_SIZE];
2664 for (i = 0; i < table->rows; ++i) {
2665 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2667 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2668 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2673 verify_standalonesig_table (VerifyContext *ctx)
2675 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2676 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2679 for (i = 0; i < table->rows; ++i) {
2680 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2682 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
2683 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2688 verify_standalonesig_table_full (VerifyContext *ctx)
2690 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2691 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2694 for (i = 0; i < table->rows; ++i) {
2695 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2697 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2698 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2703 verify_eventmap_table (VerifyContext *ctx)
2705 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2706 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2709 for (i = 0; i < table->rows; ++i) {
2710 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2712 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2713 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2715 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2716 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2718 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2722 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2724 verify_event_table (VerifyContext *ctx)
2726 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2727 guint32 data [MONO_EVENT_SIZE];
2730 for (i = 0; i < table->rows; ++i) {
2731 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2733 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2734 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2736 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2737 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2739 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2740 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2745 verify_event_table_full (VerifyContext *ctx)
2747 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2748 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2749 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2750 gboolean found_add, found_remove;
2753 for (i = 0; i < table->rows; ++i) {
2754 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2756 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2757 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2759 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2761 //first we move to the first row for this event
2763 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2767 //now move forward looking for AddOn and RemoveOn rows
2768 found_add = found_remove = FALSE;
2769 while (idx < sema_table->rows) {
2770 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2771 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2773 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2775 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2776 found_remove = TRUE;
2777 if (found_add && found_remove)
2783 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2785 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2790 verify_propertymap_table (VerifyContext *ctx)
2792 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2793 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2796 for (i = 0; i < table->rows; ++i) {
2797 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2799 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2800 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2802 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2803 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2805 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2809 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2811 verify_property_table (VerifyContext *ctx)
2813 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2814 guint32 data [MONO_PROPERTY_SIZE];
2817 for (i = 0; i < table->rows; ++i) {
2818 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2820 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2821 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2823 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2824 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2826 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2827 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2829 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2830 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2831 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2837 verify_methodimpl_table (VerifyContext *ctx)
2839 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2840 guint32 data [MONO_METHODIMPL_SIZE];
2843 for (i = 0; i < table->rows; ++i) {
2844 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2846 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2847 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2849 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2850 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2852 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2853 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2855 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2856 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2858 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2859 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2864 verify_moduleref_table (VerifyContext *ctx)
2866 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2867 guint32 data [MONO_MODULEREF_SIZE];
2870 for (i = 0; i < table->rows; ++i) {
2871 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2873 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2874 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2879 verify_typespec_table (VerifyContext *ctx)
2881 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2882 guint32 data [MONO_TYPESPEC_SIZE];
2885 for (i = 0; i < table->rows; ++i) {
2886 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2888 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
2889 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2894 verify_typespec_table_full (VerifyContext *ctx)
2896 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2897 guint32 data [MONO_TYPESPEC_SIZE];
2900 for (i = 0; i < table->rows; ++i) {
2901 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2903 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2904 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2908 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
2910 verify_implmap_table (VerifyContext *ctx)
2912 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2913 guint32 data [MONO_IMPLMAP_SIZE], cconv;
2916 for (i = 0; i < table->rows; ++i) {
2917 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2919 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2920 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2922 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2923 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2924 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2926 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2927 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2929 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2930 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2932 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2933 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2935 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2936 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2938 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
2939 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2944 verify_fieldrva_table (VerifyContext *ctx)
2946 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2947 guint32 data [MONO_FIELD_RVA_SIZE];
2950 for (i = 0; i < table->rows; ++i) {
2951 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2953 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2954 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2956 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2957 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2961 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
2963 verify_assembly_table (VerifyContext *ctx)
2965 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2966 guint32 data [MONO_ASSEMBLY_SIZE], hash;
2969 if (table->rows > 1)
2970 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2972 for (i = 0; i < table->rows; ++i) {
2973 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2975 hash = data [MONO_ASSEMBLY_HASH_ALG];
2976 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2977 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2979 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2980 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2982 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
2983 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2985 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2986 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2988 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2989 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2993 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2995 verify_assemblyref_table (VerifyContext *ctx)
2997 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2998 guint32 data [MONO_ASSEMBLYREF_SIZE];
3001 for (i = 0; i < table->rows; ++i) {
3002 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3004 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3005 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3007 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3008 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3010 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3011 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3013 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3014 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3016 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3017 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3021 #define INVALID_FILE_FLAGS_BITS ~(1)
3023 verify_file_table (VerifyContext *ctx)
3025 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3026 guint32 data [MONO_FILE_SIZE];
3029 for (i = 0; i < table->rows; ++i) {
3030 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3032 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3033 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3035 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3036 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3038 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3039 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3043 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3045 verify_exportedtype_table (VerifyContext *ctx)
3047 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3048 guint32 data [MONO_EXP_TYPE_SIZE];
3051 for (i = 0; i < table->rows; ++i) {
3052 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3054 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3055 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3057 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3058 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3060 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3061 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3063 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3064 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3066 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3067 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3069 /*nested type can't have a namespace*/
3070 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3071 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3075 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3077 verify_manifest_resource_table (VerifyContext *ctx)
3079 MonoCLIImageInfo *iinfo = ctx->image->image_info;
3080 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3081 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3082 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3085 resources_size = ch->ch_resources.size;
3087 for (i = 0; i < table->rows; ++i) {
3088 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3090 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3091 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3093 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3094 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3096 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3097 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3099 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3100 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3102 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3103 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3105 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3106 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])));
3108 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3109 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3111 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3112 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3117 verify_nested_class_table (VerifyContext *ctx)
3119 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3120 guint32 data [MONO_NESTED_CLASS_SIZE];
3123 for (i = 0; i < table->rows; ++i) {
3124 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3126 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3127 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3128 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3129 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3130 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3131 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3135 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3137 verify_generic_param_table (VerifyContext *ctx)
3139 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3140 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3141 int i, param_number = 0;
3143 for (i = 0; i < table->rows; ++i) {
3144 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3146 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3147 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3149 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3150 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3152 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3153 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3155 token = data [MONO_GENERICPARAM_OWNER];
3157 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3158 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3160 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3161 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3163 if (token != last_token) {
3168 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3169 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));
3176 verify_method_spec_table (VerifyContext *ctx)
3178 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3179 guint32 data [MONO_METHODSPEC_SIZE];
3182 for (i = 0; i < table->rows; ++i) {
3183 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3185 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3186 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3188 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3189 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3191 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3192 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3197 verify_method_spec_table_full (VerifyContext *ctx)
3199 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3200 guint32 data [MONO_METHODSPEC_SIZE];
3203 for (i = 0; i < table->rows; ++i) {
3204 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3206 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3207 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3212 verify_generic_param_constraint_table (VerifyContext *ctx)
3214 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3215 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3218 for (i = 0; i < table->rows; ++i) {
3219 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3221 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3222 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3224 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3225 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3227 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3228 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3235 const char *name_space;
3236 guint32 resolution_scope;
3240 typedef_hash (gconstpointer _key)
3242 const TypeDefUniqueId *key = _key;
3243 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3247 typedef_equals (gconstpointer _a, gconstpointer _b)
3249 const TypeDefUniqueId *a = _a;
3250 const TypeDefUniqueId *b = _b;
3251 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3255 verify_typedef_table_global_constraints (VerifyContext *ctx)
3258 guint32 data [MONO_TYPEDEF_SIZE];
3259 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3260 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3261 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3262 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3264 for (i = 0; i < table->rows; ++i) {
3266 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3267 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3269 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3270 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3271 type->resolution_scope = 0;
3273 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3274 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3275 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3276 g_assert (res >= 0);
3278 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3279 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3282 if (g_hash_table_lookup (unique_types, type)) {
3283 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));
3284 g_hash_table_destroy (unique_types);
3288 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3291 g_hash_table_destroy (unique_types);
3295 verify_typeref_table_global_constraints (VerifyContext *ctx)
3298 guint32 data [MONO_TYPEREF_SIZE];
3299 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3300 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3302 for (i = 0; i < table->rows; ++i) {
3303 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3304 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3306 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3307 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3308 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3310 if (g_hash_table_lookup (unique_types, type)) {
3311 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));
3312 g_hash_table_destroy (unique_types);
3316 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3319 g_hash_table_destroy (unique_types);
3323 verify_tables_data_global_constraints (VerifyContext *ctx)
3325 verify_typeref_table_global_constraints (ctx);
3327 verify_typedef_table_global_constraints (ctx);
3331 verify_tables_data (VerifyContext *ctx)
3333 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3334 guint32 size = 0, tables_offset;
3337 for (i = 0; i < 0x2D; ++i) {
3338 MonoTableInfo *table = &ctx->image->tables [i];
3340 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3341 if (tmp_size < size) {
3349 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3351 tables_offset = ctx->image->tables_base - ctx->data;
3352 if (!bounds_check_offset (&tables_area, tables_offset, size))
3353 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)));
3355 verify_module_table (ctx);
3357 verify_typeref_table (ctx);
3359 verify_typedef_table (ctx);
3361 verify_field_table (ctx);
3363 verify_method_table (ctx);
3365 verify_param_table (ctx);
3367 verify_interfaceimpl_table (ctx);
3369 verify_memberref_table (ctx);
3371 verify_constant_table (ctx);
3373 verify_cattr_table (ctx);
3375 verify_field_marshal_table (ctx);
3377 verify_decl_security_table (ctx);
3379 verify_class_layout_table (ctx);
3381 verify_field_layout_table (ctx);
3383 verify_standalonesig_table (ctx);
3385 verify_eventmap_table (ctx);
3387 verify_event_table (ctx);
3389 verify_propertymap_table (ctx);
3391 verify_property_table (ctx);
3393 verify_methodimpl_table (ctx);
3395 verify_moduleref_table (ctx);
3397 verify_typespec_table (ctx);
3399 verify_implmap_table (ctx);
3401 verify_fieldrva_table (ctx);
3403 verify_assembly_table (ctx);
3405 verify_assemblyref_table (ctx);
3407 verify_file_table (ctx);
3409 verify_exportedtype_table (ctx);
3411 verify_manifest_resource_table (ctx);
3413 verify_nested_class_table (ctx);
3415 verify_generic_param_table (ctx);
3417 verify_method_spec_table (ctx);
3419 verify_generic_param_constraint_table (ctx);
3421 verify_tables_data_global_constraints (ctx);
3425 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
3427 memset (ctx, 0, sizeof (VerifyContext));
3429 ctx->report_error = error_list != NULL;
3430 ctx->report_warning = FALSE; //export this setting in the API
3432 ctx->size = image->raw_data_len;
3433 ctx->data = image->raw_data;
3437 cleanup_context (VerifyContext *ctx, GSList **error_list)
3439 g_free (ctx->sections);
3441 *error_list = ctx->errors;
3443 mono_free_verify_list (ctx->errors);
3448 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3452 if (!mono_verifier_is_enabled_for_image (image))
3455 init_verify_context (&ctx, image, error_list);
3456 ctx.stage = STAGE_PE;
3458 verify_msdos_header (&ctx);
3460 verify_pe_header (&ctx);
3462 verify_pe_optional_header (&ctx);
3464 load_section_table (&ctx);
3466 load_data_directories (&ctx);
3468 verify_import_table (&ctx);
3470 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3471 verify_resources_table (&ctx);
3474 return cleanup_context (&ctx, error_list);
3478 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3482 if (!mono_verifier_is_enabled_for_image (image))
3485 init_verify_context (&ctx, image, error_list);
3486 ctx.stage = STAGE_CLI;
3488 verify_cli_header (&ctx);
3490 verify_metadata_header (&ctx);
3492 verify_tables_schema (&ctx);
3495 return cleanup_context (&ctx, error_list);
3500 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3501 * Other verification checks are meant to be done lazily by the runtime. Those include:
3502 * blob items (signatures, method headers, custom attributes, etc)
3503 * type semantics related
3505 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3507 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3508 * operation still need more checking.
3511 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3515 if (!mono_verifier_is_enabled_for_image (image))
3518 init_verify_context (&ctx, image, error_list);
3519 ctx.stage = STAGE_TABLES;
3521 verify_tables_data (&ctx);
3523 return cleanup_context (&ctx, error_list);
3528 * Verifies all other constraints.
3531 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3535 if (!mono_verifier_is_enabled_for_image (image))
3538 init_verify_context (&ctx, image, error_list);
3539 ctx.stage = STAGE_TABLES;
3541 verify_typedef_table_full (&ctx);
3543 verify_field_table_full (&ctx);
3545 verify_method_table_full (&ctx);
3547 verify_memberref_table_full (&ctx);
3549 verify_cattr_table_full (&ctx);
3551 verify_field_marshal_table_full (&ctx);
3553 verify_decl_security_table_full (&ctx);
3555 verify_standalonesig_table_full (&ctx);
3557 verify_event_table_full (&ctx);
3559 verify_typespec_table_full (&ctx);
3561 verify_method_spec_table_full (&ctx);
3564 return cleanup_context (&ctx, error_list);
3568 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3572 if (!mono_verifier_is_enabled_for_image (image))
3575 init_verify_context (&ctx, image, error_list);
3576 ctx.stage = STAGE_TABLES;
3578 is_valid_field_signature (&ctx, offset);
3579 return cleanup_context (&ctx, error_list);
3583 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3587 if (!mono_verifier_is_enabled_for_image (image))
3590 init_verify_context (&ctx, image, error_list);
3591 ctx.stage = STAGE_TABLES;
3593 is_valid_method_header (&ctx, offset);
3594 return cleanup_context (&ctx, error_list);
3598 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3602 if (!mono_verifier_is_enabled_for_image (image))
3605 init_verify_context (&ctx, image, error_list);
3606 ctx.stage = STAGE_TABLES;
3608 is_valid_method_signature (&ctx, offset);
3609 return cleanup_context (&ctx, error_list);
3613 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3617 if (!mono_verifier_is_enabled_for_image (image))
3620 init_verify_context (&ctx, image, error_list);
3621 ctx.stage = STAGE_TABLES;
3623 is_valid_method_or_field_signature (&ctx, offset);
3624 return cleanup_context (&ctx, error_list);
3628 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3632 if (!mono_verifier_is_enabled_for_image (image))
3635 init_verify_context (&ctx, image, error_list);
3636 ctx.stage = STAGE_TABLES;
3638 is_valid_standalonesig_blob (&ctx, offset);
3639 return cleanup_context (&ctx, error_list);
3643 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3647 if (!mono_verifier_is_enabled_for_image (image))
3650 init_verify_context (&ctx, image, error_list);
3651 ctx.stage = STAGE_TABLES;
3653 is_valid_typespec_blob (&ctx, offset);
3654 return cleanup_context (&ctx, error_list);
3658 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3662 if (!mono_verifier_is_enabled_for_image (image))
3665 init_verify_context (&ctx, image, error_list);
3666 ctx.stage = STAGE_TABLES;
3668 is_valid_methodspec_blog (&ctx, offset);
3669 return cleanup_context (&ctx, error_list);
3674 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3680 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3686 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3692 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3698 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3704 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3710 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3716 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3722 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3728 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3734 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3739 #endif /* DISABLE_VERIFIER */