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; \
252 #define ADD_ERROR(__ctx, __msg) \
254 if ((__ctx)->report_error) \
255 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
256 (__ctx)->valid = 0; \
260 #define FAIL(__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 CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
270 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
272 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
273 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
275 #if SIZEOF_VOID_P == 4
276 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
278 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
281 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
282 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
285 dword_align (const char *ptr)
287 #if SIZEOF_VOID_P == 8
288 return (const char *) (((guint64) (ptr + 3)) & ~3);
290 return (const char *) (((guint32) (ptr + 3)) & ~3);
295 pe_signature_offset (VerifyContext *ctx)
297 return read32 (ctx->data + 0x3c);
301 pe_header_offset (VerifyContext *ctx)
303 return read32 (ctx->data + 0x3c) + 4;
307 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
311 if (rva + size < rva) //overflow
314 if (ctx->stage > STAGE_PE) {
315 MonoCLIImageInfo *iinfo = ctx->image->image_info;
316 const int top = iinfo->cli_section_count;
317 MonoSectionTable *tables = iinfo->cli_section_tables;
320 for (i = 0; i < top; i++) {
321 guint32 base = tables->st_virtual_address;
322 guint32 end = base + tables->st_raw_data_size;
324 if (rva >= base && rva + size <= end)
327 /*if ((addr >= tables->st_virtual_address) &&
328 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
330 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
340 for (i = 0; i < ctx->section_count; ++i) {
341 guint32 base = ctx->sections [i].baseRVA;
342 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
343 if (rva >= base && rva + size <= end)
350 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
352 if (dir->translated_offset > offset)
354 if (dir->size < size)
356 return offset + size <= dir->translated_offset + dir->size;
360 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
362 if (off->offset > offset)
365 if (off->size < size)
368 return offset + size <= off->offset + off->size;
372 translate_rva (VerifyContext *ctx, guint32 rva)
376 if (ctx->stage > STAGE_PE)
377 return mono_cli_rva_image_map (ctx->image, rva);
382 for (i = 0; i < ctx->section_count; ++i) {
383 guint32 base = ctx->sections [i].baseRVA;
384 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
385 if (rva >= base && rva <= end) {
386 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
388 return res >= ctx->size ? INVALID_OFFSET : res;
392 return INVALID_OFFSET;
396 verify_msdos_header (VerifyContext *ctx)
400 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
401 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
402 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
403 lfanew = pe_signature_offset (ctx);
404 if (lfanew > ctx->size - 4)
405 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
409 verify_pe_header (VerifyContext *ctx)
411 guint32 offset = pe_signature_offset (ctx);
412 const char *pe_header = ctx->data + offset;
413 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
414 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
418 if (offset > ctx->size - 20)
419 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
420 if (read16 (pe_header) != 0x14c)
421 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
425 verify_pe_optional_header (VerifyContext *ctx)
427 guint32 offset = pe_header_offset (ctx);
428 guint32 header_size, file_alignment;
429 const char *pe_header = ctx->data + offset;
430 const char *pe_optional_header = pe_header + 20;
432 header_size = read16 (pe_header + 16);
435 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
436 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
438 if (offset > ctx->size - header_size || header_size > ctx->size)
439 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
441 if (read16 (pe_optional_header) == 0x10b) {
442 if (header_size != 224)
443 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
445 /* LAMESPEC MS plays around this value and ignore it during validation
446 if (read32 (pe_optional_header + 28) != 0x400000)
447 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
448 if (read32 (pe_optional_header + 32) != 0x2000)
449 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
450 file_alignment = read32 (pe_optional_header + 36);
451 if (file_alignment != 0x200 && file_alignment != 0x1000)
452 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
453 /* All the junk in the middle is irrelevant, specially for mono. */
454 if (read32 (pe_optional_header + 92) > 0x10)
455 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
457 if (read16 (pe_optional_header) == 0x20B)
458 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
460 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
465 load_section_table (VerifyContext *ctx)
468 SectionHeader *sections;
469 guint32 offset = pe_header_offset (ctx);
470 const char *ptr = ctx->data + offset;
471 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
473 offset += 244;/*FIXME, this constant is different under PE32+*/
476 if (num_sections * 40 > ctx->size - offset)
477 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
479 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
480 for (i = 0; i < num_sections; ++i) {
481 sections [i].size = read32 (ptr + 8);
482 sections [i].baseRVA = read32 (ptr + 12);
483 sections [i].baseOffset = read32 (ptr + 20);
484 sections [i].rellocationsRVA = read32 (ptr + 24);
485 sections [i].numberOfRelocations = read16 (ptr + 32);
489 ptr = ctx->data + offset; /*reset it to the beggining*/
490 for (i = 0; i < num_sections; ++i) {
491 guint32 raw_size, flags;
492 if (sections [i].baseOffset == 0)
493 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
494 if (sections [i].baseOffset >= ctx->size)
495 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
496 if (sections [i].size > ctx->size - sections [i].baseOffset)
497 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
499 raw_size = read32 (ptr + 16);
500 if (raw_size < sections [i].size)
501 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
503 if (raw_size > ctx->size - sections [i].baseOffset)
504 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
506 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
507 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
509 flags = read32 (ptr + 36);
510 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
511 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
512 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
519 is_valid_data_directory (int i)
521 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
522 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
526 load_data_directories (VerifyContext *ctx)
528 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
529 const char *ptr = ctx->data + offset;
532 for (i = 0; i < 16; ++i) {
533 guint32 rva = read32 (ptr);
534 guint32 size = read32 (ptr + 4);
536 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
537 if (i == CERTIFICATE_TABLE_IDX) {
541 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
542 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
544 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
545 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
547 ctx->data_directories [i].rva = rva;
548 ctx->data_directories [i].size = size;
549 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
555 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
557 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
560 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
563 guint32 hint_table_rva;
565 import_rva = translate_rva (ctx, import_rva);
566 g_assert (import_rva != INVALID_OFFSET);
568 hint_table_rva = read32 (ctx->data + import_rva);
569 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
570 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
572 hint_table_rva = translate_rva (ctx, hint_table_rva);
573 g_assert (hint_table_rva != INVALID_OFFSET);
574 ptr = ctx->data + hint_table_rva + 2;
576 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
577 char name[SIZE_OF_CORMAIN];
578 memcpy (name, ptr, SIZE_OF_CORMAIN);
579 name [SIZE_OF_CORMAIN - 1] = 0;
580 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
585 verify_import_table (VerifyContext *ctx)
587 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
588 guint32 offset = it.translated_offset;
589 const char *ptr = ctx->data + offset;
590 guint32 name_rva, ilt_rva, iat_rva;
592 g_assert (offset != INVALID_OFFSET);
595 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
597 ilt_rva = read32 (ptr);
598 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
599 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
601 name_rva = read32 (ptr + 12);
602 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
603 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
605 iat_rva = read32 (ptr + 16);
607 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
608 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
610 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
611 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));
615 name_rva = translate_rva (ctx, name_rva);
616 g_assert (name_rva != INVALID_OFFSET);
617 ptr = ctx->data + name_rva;
619 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
620 char name[SIZE_OF_MSCOREE];
621 memcpy (name, ptr, SIZE_OF_MSCOREE);
622 name [SIZE_OF_MSCOREE - 1] = 0;
623 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
628 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
633 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
637 verify_resources_table (VerifyContext *ctx)
639 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
641 guint16 named_entries, id_entries;
642 const char *ptr, *root, *end;
648 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));
650 offset = it.translated_offset;
651 root = ptr = ctx->data + offset;
652 end = root + it.size;
654 g_assert (offset != INVALID_OFFSET);
656 named_entries = read16 (ptr + 12);
657 id_entries = read16 (ptr + 14);
659 if ((named_entries + id_entries) * 8 + 16 > it.size)
660 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));
662 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
663 if (named_entries || id_entries)
664 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
668 /*----------nothing from here on can use data_directory---*/
671 get_data_dir (VerifyContext *ctx, int idx)
673 MonoCLIImageInfo *iinfo = ctx->image->image_info;
674 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
678 res.rva = entry->rva;
679 res.size = entry->size;
680 res.translated_offset = translate_rva (ctx, res.rva);
685 verify_cli_header (VerifyContext *ctx)
687 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
693 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
696 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
698 offset = it.translated_offset;
699 ptr = ctx->data + offset;
701 g_assert (offset != INVALID_OFFSET);
703 if (read16 (ptr) != 72)
704 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
706 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
707 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
710 if (!read32 (ptr + 8) || !read32 (ptr + 12))
711 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
713 if ((read32 (ptr + 16) & ~0x0001000B) != 0)
714 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
717 for (i = 0; i < 6; ++i) {
718 guint32 rva = read32 (ptr);
719 guint32 size = read32 (ptr + 4);
721 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
722 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
727 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
732 pad4 (guint32 offset)
734 if (offset & 0x3) //pad to the next 4 byte boundary
735 offset = (offset & ~0x3) + 4;
740 verify_metadata_header (VerifyContext *ctx)
743 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
747 offset = it.translated_offset;
748 ptr = ctx->data + offset;
749 g_assert (offset != INVALID_OFFSET);
751 //build a directory entry for the metadata root
753 it.rva = read32 (ptr);
755 it.size = read32 (ptr);
756 it.translated_offset = offset = translate_rva (ctx, it.rva);
758 ptr = ctx->data + offset;
759 g_assert (offset != INVALID_OFFSET);
762 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
764 if (read32 (ptr) != 0x424A5342)
765 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
767 offset = pad4 (offset + 16 + read32 (ptr + 12));
769 if (!bounds_check_datadir (&it, offset, 4))
770 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));
772 ptr = ctx->data + offset; //move to streams header
774 if (read16 (ptr + 2) < 3)
775 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob"));
780 for (i = 0; i < 5; ++i) {
781 guint32 stream_off, stream_size;
782 int string_size, stream_idx;
784 if (!bounds_check_datadir (&it, offset, 8))
785 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));
787 stream_off = it.translated_offset + read32 (ptr);
788 stream_size = read32 (ptr + 4);
790 if (!bounds_check_datadir (&it, stream_off, stream_size))
791 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
796 for (string_size = 0; string_size < 32; ++string_size) {
797 if (!bounds_check_datadir (&it, offset++, 1))
798 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
799 if (!ptr [string_size])
803 if (ptr [string_size])
804 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
806 if (!strncmp ("#Strings", ptr, 9))
807 stream_idx = STRINGS_STREAM;
808 else if (!strncmp ("#US", ptr, 4))
809 stream_idx = USER_STRINGS_STREAM;
810 else if (!strncmp ("#Blob", ptr, 6))
811 stream_idx = BLOB_STREAM;
812 else if (!strncmp ("#GUID", ptr, 6))
813 stream_idx = GUID_STREAM;
814 else if (!strncmp ("#~", ptr, 3))
815 stream_idx = TILDE_STREAM;
817 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
819 if (ctx->metadata_streams [stream_idx].offset != 0)
820 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
822 ctx->metadata_streams [stream_idx].offset = stream_off;
823 ctx->metadata_streams [stream_idx].size = stream_size;
825 offset = pad4 (offset);
826 ptr = ctx->data + offset;
829 if (!ctx->metadata_streams [TILDE_STREAM].size)
830 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
831 if (!ctx->metadata_streams [GUID_STREAM].size)
832 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
833 if (!ctx->metadata_streams [BLOB_STREAM].size)
834 ADD_ERROR (ctx, g_strdup_printf ("Metadata blob stream missing"));
839 verify_tables_schema (VerifyContext *ctx)
841 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
842 unsigned offset = tables_area.offset;
843 const char *ptr = ctx->data + offset;
844 guint64 valid_tables;
848 //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
849 if (tables_area.size < 24)
850 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
852 //printf ("ptr %x %x\n", ptr[4], ptr[5]);
853 if (ptr [4] != 2 && ptr [4] != 1)
854 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
856 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
858 if ((ptr [6] & ~0x7) != 0)
859 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]));
861 valid_tables = read64 (ptr + 8);
863 for (i = 0; i < 64; ++i) {
864 if (!(valid_tables & ((guint64)1 << i)))
867 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
868 Unused: 0x1E 0x1F 0x2D-0x3F
869 We don't care about the MS extensions.*/
870 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
871 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
872 if (i == 0x1E || i == 0x1F || i >= 0x2D)
873 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
877 if (tables_area.size < 24 + count * 4)
878 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));
881 for (i = 0; i < 64; ++i) {
882 if (valid_tables & ((guint64)1 << i)) {
883 guint32 row_count = read32 (ptr);
884 if (row_count > (1 << 24) - 1)
885 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
891 /*----------nothing from here on can use data_directory or metadata_streams ---*/
894 get_col_offset (VerifyContext *ctx, int table, int column)
896 guint32 bitfield = ctx->image->tables [table].size_bitfield;
900 offset += mono_metadata_table_size (bitfield, column);
906 get_col_size (VerifyContext *ctx, int table, int column)
908 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
912 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
915 res.offset = header->data - ctx->data;
916 res.size = header->size;
922 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
924 OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
926 const char *data = ctx->data + strings.offset;
928 if (offset >= strings.size)
930 if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing
933 if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
935 return allow_empty || length > 0;
939 is_valid_string (VerifyContext *ctx, guint32 offset)
941 return is_valid_string_full (ctx, offset, TRUE);
945 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
947 return is_valid_string_full (ctx, offset, FALSE);
951 is_valid_guid (VerifyContext *ctx, guint32 offset)
953 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
954 return guids.size >= 8 && guids.size - 8 >= offset;
958 get_coded_index_token (int token_kind, guint32 coded_token)
960 guint32 bits = coded_index_desc [token_kind];
961 return coded_token >> bits;
965 get_coded_index_table (int kind, guint32 coded_token)
967 guint32 idx, bits = coded_index_desc [kind];
969 idx = coded_token & ((1 << bits) - 1);
970 return coded_index_desc [kind + idx];
974 make_coded_token (int kind, guint32 table, guint32 table_idx)
976 guint32 bits = coded_index_desc [kind++];
977 guint32 tables = coded_index_desc [kind++];
979 for (i = 0; i < tables; ++i) {
980 if (coded_index_desc [kind++] == table)
981 return ((table_idx + 1) << bits) | i;
983 g_assert_not_reached ();
988 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
990 guint32 bits = coded_index_desc [token_kind++];
991 guint32 table_count = coded_index_desc [token_kind++];
992 guint32 table = coded_token & ((1 << bits) - 1);
993 guint32 token = coded_token >> bits;
995 if (table >= table_count)
998 /*token_kind points to the first table idx*/
999 table = coded_index_desc [token_kind + table];
1001 if (table == INVALID_TABLE)
1003 return token <= ctx->image->tables [table].rows;
1010 MonoTableInfo *table;
1014 token_locator (const void *a, const void *b)
1016 RowLocator *loc = (RowLocator *)a;
1017 unsigned const char *row = (unsigned const char *)b;
1018 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1020 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1021 return (int)loc->token - (int)token;
1025 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1027 MonoTableInfo *tinfo = &ctx->image->tables [table];
1029 const char *res, *base;
1030 locator.token = coded_token;
1031 locator.col_offset = get_col_offset (ctx, table, column);
1032 locator.col_size = get_col_size (ctx, table, column);
1033 locator.table = tinfo;
1037 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) );
1038 res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1042 return (res - base) / tinfo->row_size;
1045 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1047 get_string_ptr (VerifyContext *ctx, guint offset)
1049 return ctx->image->heap_strings.data + offset;
1052 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1054 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1057 return strcmp (str, "");
1059 return strcmp (str, get_string_ptr (ctx, offset));
1063 mono_verifier_is_corlib (MonoImage *image)
1065 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
1066 TRUE : mono_security_core_clr_is_platform_image (image);
1068 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1072 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1074 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1078 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1081 const unsigned char *ptr = (const unsigned char *)_ptr;
1089 if ((b & 0x80) == 0) {
1092 } else if ((b & 0x40) == 0) {
1096 *value = ((b & 0x3f) << 8 | ptr [1]);
1101 *value = ((b & 0x1f) << 24) |
1111 decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
1113 MonoStreamHeader blob = ctx->image->heap_blob;
1114 guint32 value, enc_size;
1116 if (offset >= blob.size)
1119 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1122 if (offset + enc_size + value < offset)
1125 if (offset + enc_size + value > blob.size)
1129 *first_byte = blob.data + offset + enc_size;
1134 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1136 const char *ptr = *_ptr;
1137 if (ptr + size > limit)
1141 *dest = *((guint8*)ptr);
1145 *dest = read16 (ptr);
1149 *dest = read32 (ptr);
1158 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1161 const char *ptr = *_ptr;
1162 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1167 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1168 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1169 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1170 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1173 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1176 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1179 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1181 const char *ptr = *_ptr;
1186 if (!safe_read8 (type, ptr, end))
1187 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1189 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1194 if (!safe_read_cint (token, ptr, end))
1195 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1197 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1198 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1206 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1208 const char *ptr = *_ptr;
1210 unsigned size, num, i;
1212 if (!safe_read8 (val, ptr, end))
1213 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1216 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1218 if (!safe_read_cint (size, ptr, end))
1219 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1221 for (i = 0; i < size; ++i) {
1222 if (!safe_read_cint (num, ptr, end))
1223 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1226 if (!safe_read_cint (size, ptr, end))
1227 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1229 for (i = 0; i < size; ++i) {
1230 if (!safe_read_cint (num, ptr, end))
1231 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1239 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1241 const char *ptr = *_ptr;
1243 unsigned count, token, i;
1245 if (!safe_read8 (type, ptr, end))
1246 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1248 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1249 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1251 if (!safe_read_cint (token, ptr, end))
1252 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1254 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1255 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1257 if (!safe_read_cint (count, ptr, end))
1258 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1261 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1263 for (i = 0; i < count; ++i) {
1264 if (!parse_type (ctx, &ptr, end))
1265 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1272 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1274 const char *ptr = *_ptr;
1278 if (!safe_read8 (type, ptr, end))
1279 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1281 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1282 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1283 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1284 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1285 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1289 if (!parse_custom_mods (ctx, &ptr, end))
1290 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1292 if (!safe_read8 (type, ptr, end))
1293 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1295 if (type != MONO_TYPE_VOID) {
1297 if (!parse_type (ctx, &ptr, end))
1298 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1302 case MONO_TYPE_VALUETYPE:
1303 case MONO_TYPE_CLASS:
1304 if (!safe_read_cint (token, ptr, end))
1305 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1307 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1308 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1312 case MONO_TYPE_MVAR:
1313 if (!safe_read_cint (token, ptr, end))
1314 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1317 case MONO_TYPE_ARRAY:
1318 if (!parse_type (ctx, &ptr, end))
1319 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1320 if (!parse_array_shape (ctx, &ptr, end))
1321 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1324 case MONO_TYPE_GENERICINST:
1325 if (!parse_generic_inst (ctx, &ptr, end))
1326 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1329 case MONO_TYPE_FNPTR:
1330 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1331 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1334 case MONO_TYPE_SZARRAY:
1335 if (!parse_custom_mods (ctx, &ptr, end))
1336 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1337 if (!parse_type (ctx, &ptr, end))
1338 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1346 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1351 if (!parse_custom_mods (ctx, _ptr, end))
1355 if (!safe_read8 (type, ptr, end))
1356 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1358 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1363 //it's a byref, update the cursor ptr
1364 if (type == MONO_TYPE_BYREF)
1367 return parse_type (ctx, _ptr, end);
1371 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1376 if (!parse_custom_mods (ctx, _ptr, end))
1380 if (!safe_read8 (type, ptr, end))
1381 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1383 if (type == MONO_TYPE_TYPEDBYREF) {
1388 //it's a byref, update the cursor ptr
1389 if (type == MONO_TYPE_BYREF)
1392 return parse_type (ctx, _ptr, end);
1396 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1399 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1400 const char *ptr = *_ptr;
1401 gboolean saw_sentinel = FALSE;
1403 if (!safe_read8 (cconv, ptr, end))
1404 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1407 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1409 if (allow_unmanaged) {
1410 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1411 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1412 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1413 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1415 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1416 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1418 if ((cconv & 0x10) && gparam_count == 0)
1419 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1421 if (allow_unmanaged && (cconv & 0x10))
1422 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1424 if (!safe_read_cint (param_count, ptr, end))
1425 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1427 if (!parse_return_type (ctx, &ptr, end))
1428 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1430 for (i = 0; i < param_count; ++i) {
1431 if (allow_sentinel) {
1432 if (!safe_read8 (type, ptr, end))
1433 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1435 if (type == MONO_TYPE_SENTINEL) {
1436 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1437 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1440 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1442 saw_sentinel = TRUE;
1448 if (!parse_param (ctx, &ptr, end))
1449 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1457 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1460 unsigned param_count = 0, i;
1461 const char *ptr = *_ptr;
1463 if (!safe_read8 (sig, ptr, end))
1464 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1466 if (sig != 0x08 && sig != 0x28)
1467 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1469 if (!safe_read_cint (param_count, ptr, end))
1470 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1472 if (!parse_custom_mods (ctx, &ptr, end))
1475 if (!parse_type (ctx, &ptr, end))
1476 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1478 for (i = 0; i < param_count; ++i) {
1479 if (!parse_type (ctx, &ptr, end))
1480 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1488 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1490 const char *ptr = *_ptr;
1491 unsigned signature = 0;
1493 if (!safe_read8 (signature, ptr, end))
1494 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1496 if (signature != 0x06)
1497 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1499 if (!parse_custom_mods (ctx, &ptr, end))
1502 if (safe_read8 (signature, ptr, end)) {
1503 if (signature != MONO_TYPE_BYREF)
1508 return parse_type (ctx, _ptr, end);
1512 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1515 unsigned locals_count = 0, i;
1516 const char *ptr = *_ptr;
1518 if (!safe_read8 (sig, ptr, end))
1519 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1522 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1524 if (!safe_read_cint (locals_count, ptr, end))
1525 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1527 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1528 if (locals_count == 0)
1529 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1532 for (i = 0; i < locals_count; ++i) {
1533 if (!safe_read8 (sig, ptr, end))
1534 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1536 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1537 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1538 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1539 if (!safe_read8 (sig, ptr, end))
1540 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1543 if (sig == MONO_TYPE_BYREF) {
1544 if (!safe_read8 (sig, ptr, end))
1545 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1546 if (sig == MONO_TYPE_TYPEDBYREF)
1547 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1550 if (sig == MONO_TYPE_TYPEDBYREF)
1555 if (!parse_type (ctx, &ptr, end))
1556 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1564 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1567 unsigned signature = 0;
1568 const char *ptr = NULL, *end;
1570 if (!decode_signature_header (ctx, offset, &size, &ptr))
1571 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1574 if (!safe_read8 (signature, ptr, end))
1575 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1578 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1581 return parse_field (ctx, &ptr, end);
1585 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1588 const char *ptr = NULL, *end;
1590 if (!decode_signature_header (ctx, offset, &size, &ptr))
1591 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1594 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1598 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1601 unsigned signature = 0;
1602 const char *ptr = NULL, *end;
1604 if (!decode_signature_header (ctx, offset, &size, &ptr))
1605 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1608 if (!safe_read8 (signature, ptr, end))
1609 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1612 if (signature == 0x06)
1613 return parse_field (ctx, &ptr, end);
1615 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1619 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1622 unsigned prolog = 0;
1623 const char *ptr = NULL, *end;
1628 if (!decode_signature_header (ctx, offset, &size, &ptr))
1629 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1632 if (!safe_read16 (prolog, ptr, end))
1633 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1636 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1642 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1644 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1645 //TODO do proper verification
1646 return blob.size >= 1 && blob.size - 1 >= offset;
1650 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1652 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1653 //TODO do proper verification
1654 return blob.size >= 1 && blob.size - 1 >= offset;
1658 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1661 unsigned signature = 0;
1662 const char *ptr = NULL, *end;
1664 if (!decode_signature_header (ctx, offset, &size, &ptr))
1665 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1668 if (!safe_read8 (signature, ptr, end))
1669 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1672 if (signature == 0x07)
1673 return parse_locals_signature (ctx, &ptr, end);
1674 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1678 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1681 const char *ptr = NULL, *end;
1683 if (!decode_signature_header (ctx, offset, &size, &ptr))
1684 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
1687 return parse_property_signature (ctx, &ptr, end);
1691 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1694 const char *ptr = NULL, *end;
1698 if (!decode_signature_header (ctx, offset, &size, &ptr))
1699 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
1702 if (!parse_custom_mods (ctx, &ptr, end))
1705 if (!safe_read8 (type, ptr, end))
1706 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
1708 if (type == MONO_TYPE_BYREF) {
1709 if (!safe_read8 (type, ptr, end))
1710 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
1711 if (type == MONO_TYPE_TYPEDBYREF)
1712 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
1715 if (type == MONO_TYPE_TYPEDBYREF)
1719 return parse_type (ctx, &ptr, end);
1723 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1726 const char *ptr = NULL, *end;
1728 unsigned count = 0, i;
1730 if (!decode_signature_header (ctx, offset, &size, &ptr))
1731 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
1734 if (!safe_read8 (type, ptr, end))
1735 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
1738 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
1740 if (!safe_read_cint (count, ptr, end))
1741 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
1744 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
1746 for (i = 0; i < count; ++i) {
1747 if (!parse_type (ctx, &ptr, end))
1748 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
1754 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
1756 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1757 guint32 entry_size, bytes;
1759 if (blob.size < offset)
1762 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1765 if (entry_size < minsize)
1768 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
1770 entry_size += bytes;
1772 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
1776 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1778 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1779 guint32 size, entry_size, bytes;
1781 if (blob.size < offset)
1782 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
1784 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1785 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
1787 if (type == MONO_TYPE_STRING) {
1788 //String is encoded as: compressed_int:len len *bytes
1791 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
1792 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
1798 case MONO_TYPE_BOOLEAN:
1803 case MONO_TYPE_CHAR:
1811 case MONO_TYPE_CLASS:
1821 g_assert_not_reached ();
1824 if (size != entry_size)
1825 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
1829 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
1830 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
1832 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
1833 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
1837 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
1838 //only 0x01, 0x40 and 0x80 are allowed
1839 #define SECTION_HEADER_INVALID_FLAGS 0x3E
1842 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1844 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
1845 unsigned header = 0;
1846 unsigned fat_header = 0, size = 0, max_stack;
1847 const char *ptr = NULL, *end;
1849 if (offset == INVALID_ADDRESS)
1850 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
1852 ptr = ctx->data + offset;
1853 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
1855 if (!safe_read8 (header, ptr, end))
1856 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
1858 switch (header & 0x3) {
1861 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
1864 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
1865 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
1870 if (!safe_read16 (fat_header, ptr, end))
1871 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
1873 size = (fat_header >> 12) & 0xF;
1875 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
1877 if (!safe_read16 (max_stack, ptr, end))
1878 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
1880 if (!safe_read32 (code_size, ptr, end))
1881 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
1883 if (!safe_read32 (local_vars_tok, ptr, end))
1884 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
1886 if (local_vars_tok) {
1887 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
1888 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
1889 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
1890 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
1893 if (fat_header & FAT_HEADER_INVALID_FLAGS)
1894 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
1896 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
1897 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
1899 if (!(fat_header & 0x08))
1905 unsigned section_header = 0, section_size = 0;
1908 ptr = dword_align (ptr);
1909 if (!safe_read32 (section_header, ptr, end))
1910 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
1912 if (section_header & SECTION_HEADER_INVALID_FLAGS)
1913 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
1915 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
1916 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
1918 if (section_size < 4)
1919 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
1921 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
1922 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
1924 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
1925 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
1927 LAMEIMPL: MS emits section_size without accounting for header size.
1928 Mono does as the spec says. section_size is header + section
1929 MS's peverify happily accepts both.
1931 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
1932 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)));
1934 /* only verify the class token is verified as the rest is done by the IL verifier*/
1935 for (i = 0; i < clauses; ++i) {
1936 unsigned flags = *(unsigned char*)ptr;
1937 unsigned class_token = 0;
1938 ptr += (is_fat ? 20 : 8);
1939 if (!safe_read32 (class_token, ptr, end))
1940 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
1941 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
1942 guint table = mono_metadata_token_table (class_token);
1943 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
1944 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
1945 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
1946 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
1951 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
1958 verify_module_table (VerifyContext *ctx)
1960 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1961 guint32 data [MONO_MODULE_SIZE];
1963 if (table->rows != 1)
1964 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1966 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1968 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1969 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1971 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1972 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1974 if (data [MONO_MODULE_ENC] != 0)
1975 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1977 if (data [MONO_MODULE_ENCBASE] != 0)
1978 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1982 verify_typeref_table (VerifyContext *ctx)
1984 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1985 guint32 data [MONO_TYPEREF_SIZE];
1988 for (i = 0; i < table->rows; ++i) {
1989 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1990 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1991 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1993 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1994 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1996 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1997 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1999 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2000 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
2004 /*bits 9,11,14,15,19,21,24-31 */
2005 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2007 verify_typedef_table (VerifyContext *ctx)
2009 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2010 guint32 data [MONO_TYPEDEF_SIZE];
2011 guint32 fieldlist = 1, methodlist = 1;
2014 if (table->rows == 0)
2015 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2017 for (i = 0; i < table->rows; ++i) {
2018 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2019 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2020 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2022 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2023 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2025 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2026 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2028 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2029 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2031 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2032 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2034 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2035 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2037 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2038 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2040 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2041 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2043 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2044 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2046 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2047 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2049 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2050 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));
2052 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2053 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2055 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2056 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2058 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2059 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));
2061 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2062 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2067 verify_typedef_table_full (VerifyContext *ctx)
2069 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2070 guint32 data [MONO_TYPEDEF_SIZE];
2073 if (table->rows == 0)
2074 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2076 for (i = 0; i < table->rows; ++i) {
2077 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2080 if (data [MONO_TYPEDEF_EXTENDS] != 0)
2081 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2085 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2086 if (data [MONO_TYPEDEF_EXTENDS])
2087 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2089 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2090 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2094 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2097 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2105 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2107 verify_field_table (VerifyContext *ctx)
2109 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2110 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2113 module_field_list = (guint32)-1;
2114 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2115 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2116 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2119 for (i = 0; i < table->rows; ++i) {
2120 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2121 flags = data [MONO_FIELD_FLAGS];
2123 if (flags & INVALID_FIELD_FLAG_BITS)
2124 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2126 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2127 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2129 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2130 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2132 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2133 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2135 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2136 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2138 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2139 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2140 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2142 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2143 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2144 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2146 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2147 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2148 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2150 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2151 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2152 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2154 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2155 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2157 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2158 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2160 //TODO verify contant flag
2162 if (i + 1 < module_field_list) {
2163 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2164 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2165 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2166 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2167 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2173 verify_field_table_full (VerifyContext *ctx)
2175 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2176 guint32 data [MONO_FIELD_SIZE];
2179 for (i = 0; i < table->rows; ++i) {
2180 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2182 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2183 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2187 /*bits 6,8,9,10,11,13,14,15*/
2188 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2190 verify_method_table (VerifyContext *ctx)
2192 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2193 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2194 guint32 paramlist = 1;
2195 gboolean is_ctor, is_cctor;
2199 module_method_list = (guint32)-1;
2200 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2201 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2202 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2205 for (i = 0; i < table->rows; ++i) {
2206 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2207 rva = data [MONO_METHOD_RVA];
2208 implflags = data [MONO_METHOD_IMPLFLAGS];
2209 flags = data [MONO_METHOD_FLAGS];
2210 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2211 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2214 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2215 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2218 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2220 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2221 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2223 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2224 is_ctor = !strcmp (".ctor", name);
2225 is_cctor = !strcmp (".cctor", name);
2227 if ((is_ctor || is_cctor) &&
2228 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2229 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2231 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2232 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2234 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2235 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2236 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2237 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2238 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2241 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2242 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2244 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2245 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2247 //XXX no checks against cas stuff 10,11,12,13)
2249 //TODO check iface with .ctor (15,16)
2251 if (i + 1 < module_method_list) {
2252 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2253 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2254 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2255 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2256 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2257 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2260 //TODO check valuetype for synchronized
2262 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2263 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2265 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
2266 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2268 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2269 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2270 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2272 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2273 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2275 //TODO check signature contents
2278 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2279 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2280 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2281 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2283 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2284 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2287 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2289 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2290 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2291 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2293 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2294 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2296 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2297 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2299 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2300 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2302 if (data [MONO_METHOD_PARAMLIST] == 0)
2303 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2305 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2306 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));
2308 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2309 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2311 paramlist = data [MONO_METHOD_PARAMLIST];
2317 verify_method_table_full (VerifyContext *ctx)
2319 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2320 guint32 data [MONO_METHOD_SIZE], rva;
2323 for (i = 0; i < table->rows; ++i) {
2324 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2325 rva = data [MONO_METHOD_RVA];
2327 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2328 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2330 if (rva && !is_valid_method_header (ctx, rva))
2331 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2336 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2338 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2339 guint32 row = *current_method;
2340 guint32 paramlist, tmp;
2343 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2344 while (row < table->rows) {
2345 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2346 if (tmp > paramlist) {
2347 *current_method = row;
2348 return tmp - paramlist;
2353 /*no more methods, all params apply to the last one*/
2354 *current_method = table->rows;
2359 #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))
2361 verify_param_table (VerifyContext *ctx)
2363 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2364 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2365 gboolean first_param = TRUE;
2368 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2369 if (table->rows > 0)
2370 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2374 remaining_params = get_next_param_count (ctx, ¤t_method);
2376 for (i = 0; i < table->rows; ++i) {
2377 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2378 flags = data [MONO_PARAM_FLAGS];
2380 if (flags & INVALID_PARAM_FLAGS_BITS)
2381 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2383 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2384 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2385 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2387 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2388 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2391 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)
2392 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2394 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2395 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2397 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2398 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2400 first_param = FALSE;
2401 sequence = data [MONO_PARAM_SEQUENCE];
2402 if (--remaining_params == 0) {
2403 remaining_params = get_next_param_count (ctx, ¤t_method);
2410 verify_interfaceimpl_table (VerifyContext *ctx)
2412 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2413 guint32 data [MONO_INTERFACEIMPL_SIZE];
2416 for (i = 0; i < table->rows; ++i) {
2417 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2418 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2419 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2421 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2422 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2424 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2425 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2430 verify_memberref_table (VerifyContext *ctx)
2432 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2433 guint32 data [MONO_MEMBERREF_SIZE];
2436 for (i = 0; i < table->rows; ++i) {
2437 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2439 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2440 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2442 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2443 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2445 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2446 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2448 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2449 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2455 verify_memberref_table_full (VerifyContext *ctx)
2457 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2458 guint32 data [MONO_MEMBERREF_SIZE];
2461 for (i = 0; i < table->rows; ++i) {
2462 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2464 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2465 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2470 verify_constant_table (VerifyContext *ctx)
2472 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2473 guint32 data [MONO_CONSTANT_SIZE], type;
2476 for (i = 0; i < table->rows; ++i) {
2477 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2478 type = data [MONO_CONSTANT_TYPE];
2480 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2481 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2483 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2484 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2486 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2487 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2489 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2490 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2495 verify_cattr_table (VerifyContext *ctx)
2497 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2498 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2501 for (i = 0; i < table->rows; ++i) {
2502 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2504 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2505 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2507 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2508 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2510 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2511 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2516 verify_cattr_table_full (VerifyContext *ctx)
2518 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2519 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2522 for (i = 0; i < table->rows; ++i) {
2523 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2525 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2526 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2531 verify_field_marshal_table (VerifyContext *ctx)
2533 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2534 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2537 for (i = 0; i < table->rows; ++i) {
2538 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2540 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2541 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2543 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2544 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2546 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2547 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2549 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2550 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2555 verify_field_marshal_table_full (VerifyContext *ctx)
2557 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2558 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2561 for (i = 0; i < table->rows; ++i) {
2562 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2564 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2565 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2570 verify_decl_security_table (VerifyContext *ctx)
2572 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2573 guint32 data [MONO_DECL_SECURITY_SIZE];
2576 for (i = 0; i < table->rows; ++i) {
2577 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2579 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2580 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2582 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2583 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2585 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2586 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2591 verify_decl_security_table_full (VerifyContext *ctx)
2593 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2594 guint32 data [MONO_DECL_SECURITY_SIZE];
2597 for (i = 0; i < table->rows; ++i) {
2598 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2600 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2601 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2606 verify_class_layout_table (VerifyContext *ctx)
2608 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2609 guint32 data [MONO_CLASS_LAYOUT_SIZE];
2612 for (i = 0; i < table->rows; ++i) {
2613 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2615 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2616 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2618 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2630 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2636 verify_field_layout_table (VerifyContext *ctx)
2638 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2639 guint32 data [MONO_FIELD_LAYOUT_SIZE];
2642 for (i = 0; i < table->rows; ++i) {
2643 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2645 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2646 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2651 verify_standalonesig_table (VerifyContext *ctx)
2653 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2654 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2657 for (i = 0; i < table->rows; ++i) {
2658 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2660 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
2661 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2666 verify_standalonesig_table_full (VerifyContext *ctx)
2668 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2669 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2672 for (i = 0; i < table->rows; ++i) {
2673 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2675 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2676 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2681 verify_eventmap_table (VerifyContext *ctx)
2683 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2684 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2687 for (i = 0; i < table->rows; ++i) {
2688 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2690 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2691 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2693 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2694 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2696 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2700 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2702 verify_event_table (VerifyContext *ctx)
2704 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2705 guint32 data [MONO_EVENT_SIZE];
2708 for (i = 0; i < table->rows; ++i) {
2709 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2711 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2712 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2714 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2715 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2717 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2718 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2723 verify_event_table_full (VerifyContext *ctx)
2725 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2726 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2727 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2728 gboolean found_add, found_remove;
2731 for (i = 0; i < table->rows; ++i) {
2732 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2734 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2735 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2737 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2739 //first we move to the first row for this event
2741 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2745 //now move forward looking for AddOn and RemoveOn rows
2746 found_add = found_remove = FALSE;
2747 while (idx < sema_table->rows) {
2748 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2749 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2751 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2753 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2754 found_remove = TRUE;
2755 if (found_add && found_remove)
2761 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2763 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2768 verify_propertymap_table (VerifyContext *ctx)
2770 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2771 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2774 for (i = 0; i < table->rows; ++i) {
2775 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2777 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2778 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2780 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2781 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2783 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2787 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2789 verify_property_table (VerifyContext *ctx)
2791 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2792 guint32 data [MONO_PROPERTY_SIZE];
2795 for (i = 0; i < table->rows; ++i) {
2796 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2798 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2799 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2801 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2802 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2804 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2805 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2807 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2808 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2809 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2815 verify_methodimpl_table (VerifyContext *ctx)
2817 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2818 guint32 data [MONO_METHODIMPL_SIZE];
2821 for (i = 0; i < table->rows; ++i) {
2822 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2824 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2825 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2827 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2828 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2830 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2831 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2833 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2834 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2836 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2837 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2842 verify_moduleref_table (VerifyContext *ctx)
2844 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2845 guint32 data [MONO_MODULEREF_SIZE];
2848 for (i = 0; i < table->rows; ++i) {
2849 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2851 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2852 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2857 verify_typespec_table (VerifyContext *ctx)
2859 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2860 guint32 data [MONO_TYPESPEC_SIZE];
2863 for (i = 0; i < table->rows; ++i) {
2864 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2866 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
2867 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2872 verify_typespec_table_full (VerifyContext *ctx)
2874 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2875 guint32 data [MONO_TYPESPEC_SIZE];
2878 for (i = 0; i < table->rows; ++i) {
2879 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2881 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2882 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2886 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
2888 verify_implmap_table (VerifyContext *ctx)
2890 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2891 guint32 data [MONO_IMPLMAP_SIZE], cconv;
2894 for (i = 0; i < table->rows; ++i) {
2895 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2897 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2898 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2900 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2901 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2902 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2904 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2905 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2907 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2908 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2910 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2911 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2913 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2914 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2916 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
2917 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2922 verify_fieldrva_table (VerifyContext *ctx)
2924 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2925 guint32 data [MONO_FIELD_RVA_SIZE];
2928 for (i = 0; i < table->rows; ++i) {
2929 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2931 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2932 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2934 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2935 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2939 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
2941 verify_assembly_table (VerifyContext *ctx)
2943 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2944 guint32 data [MONO_ASSEMBLY_SIZE], hash;
2947 if (table->rows > 1)
2948 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2950 for (i = 0; i < table->rows; ++i) {
2951 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2953 hash = data [MONO_ASSEMBLY_HASH_ALG];
2954 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2955 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2957 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2958 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2960 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
2961 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2963 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2964 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2966 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2967 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2971 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2973 verify_assemblyref_table (VerifyContext *ctx)
2975 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2976 guint32 data [MONO_ASSEMBLYREF_SIZE];
2979 for (i = 0; i < table->rows; ++i) {
2980 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2982 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2983 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2985 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
2986 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2988 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2989 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
2991 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
2992 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
2994 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
2995 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
2999 #define INVALID_FILE_FLAGS_BITS ~(1)
3001 verify_file_table (VerifyContext *ctx)
3003 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3004 guint32 data [MONO_FILE_SIZE];
3007 for (i = 0; i < table->rows; ++i) {
3008 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3010 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3011 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3013 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3014 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3016 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3017 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3021 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3023 verify_exportedtype_table (VerifyContext *ctx)
3025 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3026 guint32 data [MONO_EXP_TYPE_SIZE];
3029 for (i = 0; i < table->rows; ++i) {
3030 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3032 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3033 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3035 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3036 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3038 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3039 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3041 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3042 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3044 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3045 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3047 /*nested type can't have a namespace*/
3048 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3049 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3053 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3055 verify_manifest_resource_table (VerifyContext *ctx)
3057 MonoCLIImageInfo *iinfo = ctx->image->image_info;
3058 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3059 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3060 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3063 resources_size = ch->ch_resources.size;
3065 for (i = 0; i < table->rows; ++i) {
3066 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3068 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3069 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3071 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3072 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3074 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3075 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3077 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3078 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3080 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3081 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3083 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3084 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])));
3086 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3087 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3089 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3090 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3095 verify_nested_class_table (VerifyContext *ctx)
3097 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3098 guint32 data [MONO_NESTED_CLASS_SIZE];
3101 for (i = 0; i < table->rows; ++i) {
3102 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3104 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3105 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3106 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3107 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3108 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3109 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3113 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3115 verify_generic_param_table (VerifyContext *ctx)
3117 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3118 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3119 int i, param_number = 0;
3121 for (i = 0; i < table->rows; ++i) {
3122 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3124 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3125 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3127 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3128 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3130 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3131 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3133 token = data [MONO_GENERICPARAM_OWNER];
3135 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3136 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3138 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3139 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3141 if (token != last_token) {
3146 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3147 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));
3154 verify_method_spec_table (VerifyContext *ctx)
3156 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3157 guint32 data [MONO_METHODSPEC_SIZE];
3160 for (i = 0; i < table->rows; ++i) {
3161 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3163 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3164 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3166 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3167 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3169 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3170 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3175 verify_method_spec_table_full (VerifyContext *ctx)
3177 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3178 guint32 data [MONO_METHODSPEC_SIZE];
3181 for (i = 0; i < table->rows; ++i) {
3182 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3184 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3185 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3190 verify_generic_param_constraint_table (VerifyContext *ctx)
3192 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3193 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3196 for (i = 0; i < table->rows; ++i) {
3197 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3199 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3200 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3202 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3203 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3205 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3206 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3211 verify_tables_data (VerifyContext *ctx)
3213 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3214 guint32 size = 0, tables_offset;
3217 for (i = 0; i < 0x2D; ++i) {
3218 MonoTableInfo *table = &ctx->image->tables [i];
3220 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3221 if (tmp_size < size) {
3229 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3231 tables_offset = ctx->image->tables_base - ctx->data;
3232 if (!bounds_check_offset (&tables_area, tables_offset, size))
3233 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)));
3235 verify_module_table (ctx);
3237 verify_typeref_table (ctx);
3239 verify_typedef_table (ctx);
3241 verify_field_table (ctx);
3243 verify_method_table (ctx);
3245 verify_param_table (ctx);
3247 verify_interfaceimpl_table (ctx);
3249 verify_memberref_table (ctx);
3251 verify_constant_table (ctx);
3253 verify_cattr_table (ctx);
3255 verify_field_marshal_table (ctx);
3257 verify_decl_security_table (ctx);
3259 verify_class_layout_table (ctx);
3261 verify_field_layout_table (ctx);
3263 verify_standalonesig_table (ctx);
3265 verify_eventmap_table (ctx);
3267 verify_event_table (ctx);
3269 verify_propertymap_table (ctx);
3271 verify_property_table (ctx);
3273 verify_methodimpl_table (ctx);
3275 verify_moduleref_table (ctx);
3277 verify_typespec_table (ctx);
3279 verify_implmap_table (ctx);
3281 verify_fieldrva_table (ctx);
3283 verify_assembly_table (ctx);
3285 verify_assemblyref_table (ctx);
3287 verify_file_table (ctx);
3289 verify_exportedtype_table (ctx);
3291 verify_manifest_resource_table (ctx);
3293 verify_nested_class_table (ctx);
3295 verify_generic_param_table (ctx);
3297 verify_method_spec_table (ctx);
3299 verify_generic_param_constraint_table (ctx);
3303 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
3305 memset (ctx, 0, sizeof (VerifyContext));
3307 ctx->report_error = error_list != NULL;
3308 ctx->report_warning = FALSE; //export this setting in the API
3310 ctx->size = image->raw_data_len;
3311 ctx->data = image->raw_data;
3315 cleanup_context (VerifyContext *ctx, GSList **error_list)
3317 g_free (ctx->sections);
3319 *error_list = ctx->errors;
3321 mono_free_verify_list (ctx->errors);
3326 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3330 if (!mono_verifier_is_enabled_for_image (image))
3333 init_verify_context (&ctx, image, error_list);
3334 ctx.stage = STAGE_PE;
3336 verify_msdos_header (&ctx);
3338 verify_pe_header (&ctx);
3340 verify_pe_optional_header (&ctx);
3342 load_section_table (&ctx);
3344 load_data_directories (&ctx);
3346 verify_import_table (&ctx);
3348 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3349 verify_resources_table (&ctx);
3352 return cleanup_context (&ctx, error_list);
3356 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3360 if (!mono_verifier_is_enabled_for_image (image))
3363 init_verify_context (&ctx, image, error_list);
3364 ctx.stage = STAGE_CLI;
3366 verify_cli_header (&ctx);
3368 verify_metadata_header (&ctx);
3370 verify_tables_schema (&ctx);
3373 return cleanup_context (&ctx, error_list);
3378 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3379 * Other verification checks are meant to be done lazily by the runtime. Those include:
3380 * blob items (signatures, method headers, custom attributes, etc)
3381 * type semantics related
3383 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3385 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3386 * operation still need more checking.
3389 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3393 if (!mono_verifier_is_enabled_for_image (image))
3396 init_verify_context (&ctx, image, error_list);
3397 ctx.stage = STAGE_TABLES;
3399 verify_tables_data (&ctx);
3401 return cleanup_context (&ctx, error_list);
3406 * Verifies all other constraints.
3409 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3413 if (!mono_verifier_is_enabled_for_image (image))
3416 init_verify_context (&ctx, image, error_list);
3417 ctx.stage = STAGE_TABLES;
3419 verify_typedef_table_full (&ctx);
3421 verify_field_table_full (&ctx);
3423 verify_method_table_full (&ctx);
3425 verify_memberref_table_full (&ctx);
3427 verify_cattr_table_full (&ctx);
3429 verify_field_marshal_table_full (&ctx);
3431 verify_decl_security_table_full (&ctx);
3433 verify_standalonesig_table_full (&ctx);
3435 verify_event_table_full (&ctx);
3437 verify_typespec_table_full (&ctx);
3439 verify_method_spec_table_full (&ctx);
3442 return cleanup_context (&ctx, error_list);
3446 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3450 if (!mono_verifier_is_enabled_for_image (image))
3453 init_verify_context (&ctx, image, error_list);
3454 ctx.stage = STAGE_TABLES;
3456 is_valid_field_signature (&ctx, offset);
3457 return cleanup_context (&ctx, error_list);
3461 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3465 if (!mono_verifier_is_enabled_for_image (image))
3468 init_verify_context (&ctx, image, error_list);
3469 ctx.stage = STAGE_TABLES;
3471 is_valid_method_header (&ctx, offset);
3472 return cleanup_context (&ctx, error_list);
3476 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3480 if (!mono_verifier_is_enabled_for_image (image))
3483 init_verify_context (&ctx, image, error_list);
3484 ctx.stage = STAGE_TABLES;
3486 is_valid_method_signature (&ctx, offset);
3487 return cleanup_context (&ctx, error_list);
3491 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3495 if (!mono_verifier_is_enabled_for_image (image))
3498 init_verify_context (&ctx, image, error_list);
3499 ctx.stage = STAGE_TABLES;
3501 is_valid_method_or_field_signature (&ctx, offset);
3502 return cleanup_context (&ctx, error_list);
3506 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3510 if (!mono_verifier_is_enabled_for_image (image))
3513 init_verify_context (&ctx, image, error_list);
3514 ctx.stage = STAGE_TABLES;
3516 is_valid_standalonesig_blob (&ctx, offset);
3517 return cleanup_context (&ctx, error_list);
3521 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3525 if (!mono_verifier_is_enabled_for_image (image))
3528 init_verify_context (&ctx, image, error_list);
3529 ctx.stage = STAGE_TABLES;
3531 is_valid_typespec_blob (&ctx, offset);
3532 return cleanup_context (&ctx, error_list);
3536 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3540 if (!mono_verifier_is_enabled_for_image (image))
3543 init_verify_context (&ctx, image, error_list);
3544 ctx.stage = STAGE_TABLES;
3546 is_valid_methodspec_blog (&ctx, offset);
3547 return cleanup_context (&ctx, error_list);
3552 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3558 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3564 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3570 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3576 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3582 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3588 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3594 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3600 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3606 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3612 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3617 #endif /* DISABLE_VERIFIER */