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,
121 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 21)
127 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
134 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
143 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
149 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
153 MONO_TABLE_MEMBERREF,
155 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
161 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
165 MONO_TABLE_ASSEMBLYREF,
166 MONO_TABLE_EXPORTEDTYPE,
168 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
174 MONO_TABLE_MEMBERREF,
177 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
181 MONO_TABLE_MODULEREF,
182 MONO_TABLE_ASSEMBLYREF,
185 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
195 guint32 translated_offset;
207 guint32 rellocationsRVA;
208 guint16 numberOfRelocations;
224 gboolean report_error;
227 DataDirectory data_directories [16];
228 guint32 section_count;
229 SectionHeader *sections;
231 OffsetAndSize metadata_streams [5]; //offset from begin of the image
234 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
236 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
237 vinfo->info.status = __status; \
238 vinfo->info.message = ( __msg); \
239 vinfo->exception_type = (__exception); \
240 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
244 #define ADD_ERROR(__ctx, __msg) \
246 if ((__ctx)->report_error) \
247 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
248 (__ctx)->valid = 0; \
252 #define FAIL(__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 CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
262 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
265 pe_signature_offset (VerifyContext *ctx)
267 return read32 (ctx->data + 0x3c);
271 pe_header_offset (VerifyContext *ctx)
273 return read32 (ctx->data + 0x3c) + 4;
277 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
281 if (rva + size < rva) //overflow
284 if (ctx->stage > STAGE_PE) {
285 MonoCLIImageInfo *iinfo = ctx->image->image_info;
286 const int top = iinfo->cli_section_count;
287 MonoSectionTable *tables = iinfo->cli_section_tables;
290 for (i = 0; i < top; i++) {
291 guint32 base = tables->st_virtual_address;
292 guint32 end = base + tables->st_raw_data_size;
294 if (rva >= base && rva + size <= end)
297 /*if ((addr >= tables->st_virtual_address) &&
298 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
300 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
310 for (i = 0; i < ctx->section_count; ++i) {
311 guint32 base = ctx->sections [i].baseRVA;
312 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
313 if (rva >= base && rva + size <= end)
320 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
322 if (dir->translated_offset > offset)
324 if (dir->size < size)
326 return offset + size <= dir->translated_offset + dir->size;
330 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
332 if (off->offset > offset)
335 if (off->size < size)
338 return offset + size <= off->offset + off->size;
342 translate_rva (VerifyContext *ctx, guint32 rva)
346 if (ctx->stage > STAGE_PE)
347 return mono_cli_rva_image_map (ctx->image, rva);
352 for (i = 0; i < ctx->section_count; ++i) {
353 guint32 base = ctx->sections [i].baseRVA;
354 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
355 if (rva >= base && rva <= end) {
356 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
358 return res >= ctx->size ? INVALID_OFFSET : res;
362 return INVALID_OFFSET;
366 verify_msdos_header (VerifyContext *ctx)
370 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
371 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
372 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
373 lfanew = pe_signature_offset (ctx);
374 if (lfanew > ctx->size - 4)
375 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
379 verify_pe_header (VerifyContext *ctx)
381 guint32 offset = pe_signature_offset (ctx);
382 const char *pe_header = ctx->data + offset;
383 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
384 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
388 if (offset > ctx->size - 20)
389 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
390 if (read16 (pe_header) != 0x14c)
391 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
395 verify_pe_optional_header (VerifyContext *ctx)
397 guint32 offset = pe_header_offset (ctx);
398 guint32 header_size, file_alignment;
399 const char *pe_header = ctx->data + offset;
400 const char *pe_optional_header = pe_header + 20;
402 header_size = read16 (pe_header + 16);
405 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
406 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
408 if (offset > ctx->size - header_size || header_size > ctx->size)
409 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
411 if (read16 (pe_optional_header) == 0x10b) {
412 if (header_size != 224)
413 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
415 /* LAMESPEC MS plays around this value and ignore it during validation
416 if (read32 (pe_optional_header + 28) != 0x400000)
417 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
418 if (read32 (pe_optional_header + 32) != 0x2000)
419 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
420 file_alignment = read32 (pe_optional_header + 36);
421 if (file_alignment != 0x200 && file_alignment != 0x1000)
422 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
423 /* All the junk in the middle is irrelevant, specially for mono. */
424 if (read32 (pe_optional_header + 92) > 0x10)
425 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
427 if (read16 (pe_optional_header) == 0x20B)
428 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
430 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
435 load_section_table (VerifyContext *ctx)
438 SectionHeader *sections;
439 guint32 offset = pe_header_offset (ctx);
440 const char *ptr = ctx->data + offset;
441 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
443 offset += 244;/*FIXME, this constant is different under PE32+*/
446 if (num_sections * 40 > ctx->size - offset)
447 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
449 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
450 for (i = 0; i < num_sections; ++i) {
451 sections [i].size = read32 (ptr + 8);
452 sections [i].baseRVA = read32 (ptr + 12);
453 sections [i].baseOffset = read32 (ptr + 20);
454 sections [i].rellocationsRVA = read32 (ptr + 24);
455 sections [i].numberOfRelocations = read16 (ptr + 32);
459 ptr = ctx->data + offset; /*reset it to the beggining*/
460 for (i = 0; i < num_sections; ++i) {
461 guint32 raw_size, flags;
462 if (sections [i].baseOffset == 0)
463 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
464 if (sections [i].baseOffset >= ctx->size)
465 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
466 if (sections [i].size > ctx->size - sections [i].baseOffset)
467 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
469 raw_size = read32 (ptr + 16);
470 if (raw_size < sections [i].size)
471 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
473 if (raw_size > ctx->size - sections [i].baseOffset)
474 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
476 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
477 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
479 flags = read32 (ptr + 36);
480 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
481 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
482 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
489 is_valid_data_directory (int i)
491 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
492 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
496 load_data_directories (VerifyContext *ctx)
498 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
499 const char *ptr = ctx->data + offset;
502 for (i = 0; i < 16; ++i) {
503 guint32 rva = read32 (ptr);
504 guint32 size = read32 (ptr + 4);
506 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
507 if (i == CERTIFICATE_TABLE_IDX) {
511 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
512 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
514 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
515 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
517 ctx->data_directories [i].rva = rva;
518 ctx->data_directories [i].size = size;
519 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
525 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
527 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
530 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
533 guint32 hint_table_rva;
535 import_rva = translate_rva (ctx, import_rva);
536 g_assert (import_rva != INVALID_OFFSET);
538 hint_table_rva = read32 (ctx->data + import_rva);
539 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
540 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
542 hint_table_rva = translate_rva (ctx, hint_table_rva);
543 g_assert (hint_table_rva != INVALID_OFFSET);
544 ptr = ctx->data + hint_table_rva + 2;
546 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
547 char name[SIZE_OF_CORMAIN];
548 memcpy (name, ptr, SIZE_OF_CORMAIN);
549 name [SIZE_OF_CORMAIN - 1] = 0;
550 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
555 verify_import_table (VerifyContext *ctx)
557 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
558 guint32 offset = it.translated_offset;
559 const char *ptr = ctx->data + offset;
560 guint32 name_rva, ilt_rva, iat_rva;
562 g_assert (offset != INVALID_OFFSET);
565 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
567 ilt_rva = read32 (ptr);
568 if (!bounds_check_virtual_address (ctx, ilt_rva, 8))
569 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
571 name_rva = read32 (ptr + 12);
572 if (!bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
573 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
575 iat_rva = read32 (ptr + 16);
576 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
577 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
579 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
580 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));
582 name_rva = translate_rva (ctx, name_rva);
583 g_assert (name_rva != INVALID_OFFSET);
584 ptr = ctx->data + name_rva;
586 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
587 char name[SIZE_OF_MSCOREE];
588 memcpy (name, ptr, SIZE_OF_MSCOREE);
589 name [SIZE_OF_MSCOREE - 1] = 0;
590 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
593 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
595 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
599 verify_resources_table (VerifyContext *ctx)
601 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
603 guint16 named_entries, id_entries;
604 const char *ptr, *root, *end;
610 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));
612 offset = it.translated_offset;
613 root = ptr = ctx->data + offset;
614 end = root + it.size;
616 g_assert (offset != INVALID_OFFSET);
618 named_entries = read16 (ptr + 12);
619 id_entries = read16 (ptr + 14);
621 if ((named_entries + id_entries) * 8 + 16 > it.size)
622 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));
624 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
625 if (named_entries || id_entries)
626 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
630 /*----------nothing from here on can use data_directory---*/
633 get_data_dir (VerifyContext *ctx, int idx)
635 MonoCLIImageInfo *iinfo = ctx->image->image_info;
636 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
640 res.rva = entry->rva;
641 res.size = entry->size;
642 res.translated_offset = translate_rva (ctx, res.rva);
647 verify_cli_header (VerifyContext *ctx)
649 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
655 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
658 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
660 offset = it.translated_offset;
661 ptr = ctx->data + offset;
663 g_assert (offset != INVALID_OFFSET);
665 if (read16 (ptr) != 72)
666 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
668 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
669 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
672 if (!read32 (ptr + 8) || !read32 (ptr + 12))
673 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
675 if ((read32 (ptr + 16) & ~0x0001000B) != 0)
676 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
679 for (i = 0; i < 6; ++i) {
680 guint32 rva = read32 (ptr);
681 guint32 size = read32 (ptr + 4);
683 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
684 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
689 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
694 pad4 (guint32 offset)
696 if (offset & 0x3) //pad to the next 4 byte boundary
697 offset = (offset & ~0x3) + 4;
702 verify_metadata_header (VerifyContext *ctx)
705 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
709 offset = it.translated_offset;
710 ptr = ctx->data + offset;
711 g_assert (offset != INVALID_OFFSET);
713 //build a directory entry for the metadata root
715 it.rva = read32 (ptr);
717 it.size = read32 (ptr);
718 it.translated_offset = offset = translate_rva (ctx, it.rva);
720 ptr = ctx->data + offset;
721 g_assert (offset != INVALID_OFFSET);
724 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
726 if (read32 (ptr) != 0x424A5342)
727 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
729 offset = pad4 (offset + 16 + read32 (ptr + 12));
731 if (!bounds_check_datadir (&it, offset, 4))
732 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));
734 ptr = ctx->data + offset; //move to streams header
736 if (read16 (ptr + 2) < 3)
737 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob"));
742 for (i = 0; i < 5; ++i) {
743 guint32 stream_off, stream_size;
744 int string_size, stream_idx;
746 if (!bounds_check_datadir (&it, offset, 8))
747 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));
749 stream_off = it.translated_offset + read32 (ptr);
750 stream_size = read32 (ptr + 4);
752 if (!bounds_check_datadir (&it, stream_off, stream_size))
753 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
758 for (string_size = 0; string_size < 32; ++string_size) {
759 if (!bounds_check_datadir (&it, offset++, 1))
760 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
761 if (!ptr [string_size])
765 if (ptr [string_size])
766 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
768 if (!strncmp ("#Strings", ptr, 9))
769 stream_idx = STRINGS_STREAM;
770 else if (!strncmp ("#US", ptr, 4))
771 stream_idx = USER_STRINGS_STREAM;
772 else if (!strncmp ("#Blob", ptr, 6))
773 stream_idx = BLOB_STREAM;
774 else if (!strncmp ("#GUID", ptr, 6))
775 stream_idx = GUID_STREAM;
776 else if (!strncmp ("#~", ptr, 3))
777 stream_idx = TILDE_STREAM;
779 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
781 if (ctx->metadata_streams [stream_idx].offset != 0)
782 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
784 ctx->metadata_streams [stream_idx].offset = stream_off;
785 ctx->metadata_streams [stream_idx].size = stream_size;
787 offset = pad4 (offset);
788 ptr = ctx->data + offset;
791 if (!ctx->metadata_streams [TILDE_STREAM].size)
792 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
793 if (!ctx->metadata_streams [GUID_STREAM].size)
794 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
795 if (!ctx->metadata_streams [BLOB_STREAM].size)
796 ADD_ERROR (ctx, g_strdup_printf ("Metadata blob stream missing"));
801 verify_tables_schema (VerifyContext *ctx)
803 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
804 unsigned offset = tables_area.offset;
805 const char *ptr = ctx->data + offset;
806 guint64 valid_tables;
810 //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
811 if (tables_area.size < 24)
812 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
814 //printf ("ptr %x %x\n", ptr[4], ptr[5]);
815 if (ptr [4] != 2 && ptr [4] != 1)
816 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
818 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
820 if ((ptr [6] & ~0x7) != 0)
821 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]));
823 valid_tables = read64 (ptr + 8);
825 for (i = 0; i < 64; ++i) {
826 if (!(valid_tables & ((guint64)1 << i)))
829 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
830 Unused: 0x1E 0x1F 0x2D-0x3F
831 We don't care about the MS extensions.*/
832 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
833 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
834 if (i == 0x1E || i == 0x1F || i >= 0x2D)
835 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
839 if (tables_area.size < 24 + count * 4)
840 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));
843 for (i = 0; i < 64; ++i) {
844 if (valid_tables & ((guint64)1 << i)) {
845 guint32 row_count = read32 (ptr);
846 if (row_count > (1 << 24) - 1)
847 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
853 /*----------nothing from here on can use data_directory or metadata_streams ---*/
856 get_col_offset (VerifyContext *ctx, int table, int column)
858 guint32 bitfield = ctx->image->tables [table].size_bitfield;
862 offset += mono_metadata_table_size (bitfield, column);
868 get_col_size (VerifyContext *ctx, int table, int column)
870 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
874 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
877 res.offset = header->data - ctx->data;
878 res.size = header->size;
884 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
886 OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
888 const char *data = ctx->data + strings.offset;
890 if (offset >= strings.size)
892 if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing
895 if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
897 return allow_empty || length > 0;
901 is_valid_string (VerifyContext *ctx, guint32 offset)
903 return is_valid_string_full (ctx, offset, TRUE);
907 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
909 return is_valid_string_full (ctx, offset, FALSE);
913 is_valid_guid (VerifyContext *ctx, guint32 offset)
915 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
916 return guids.size >= 8 && guids.size - 8 >= offset;
920 get_coded_index_token (int token_kind, guint32 coded_token)
922 guint32 bits = coded_index_desc [token_kind];
923 return coded_token >> bits;
927 get_coded_index_table (int kind, guint32 coded_token)
929 guint32 idx, bits = coded_index_desc [kind];
931 idx = coded_token & ((1 << bits) - 1);
932 return coded_index_desc [kind + idx];
936 make_coded_token (int kind, guint32 table, guint32 table_idx)
938 guint32 bits = coded_index_desc [kind++];
939 guint32 tables = coded_index_desc [kind++];
941 for (i = 0; i < tables; ++i) {
942 if (coded_index_desc [kind++] == table)
943 return ((table_idx + 1) << bits) | i;
945 g_assert_not_reached ();
950 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
952 guint32 bits = coded_index_desc [token_kind++];
953 guint32 table_count = coded_index_desc [token_kind++];
954 guint32 table = coded_token & ((1 << bits) - 1);
955 guint32 token = coded_token >> bits;
957 if (table >= table_count)
960 /*token_kind points to the first table idx*/
961 table = coded_index_desc [token_kind + table];
963 if (table == INVALID_TABLE)
965 return token <= ctx->image->tables [table].rows;
972 MonoTableInfo *table;
976 token_locator (const void *a, const void *b)
978 RowLocator *loc = (RowLocator *)a;
979 unsigned const char *row = (unsigned const char *)b;
980 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
982 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
983 return (int)loc->token - (int)token;
987 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
989 MonoTableInfo *tinfo = &ctx->image->tables [table];
991 const char *res, *base;
992 locator.token = coded_token;
993 locator.col_offset = get_col_offset (ctx, table, column);
994 locator.col_size = get_col_size (ctx, table, column);
995 locator.table = tinfo;
999 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) );
1000 res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1004 return (res - base) / tinfo->row_size;
1007 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1009 get_string_ptr (VerifyContext *ctx, guint offset)
1011 return ctx->image->heap_strings.data + offset;
1014 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1016 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1019 return strcmp (str, "");
1021 return strcmp (str, get_string_ptr (ctx, offset));
1025 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1027 return ctx->is_corlib && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAME]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAMESPACE]);
1031 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1034 const unsigned char *ptr = (const unsigned char *)_ptr;
1042 if ((b & 0x80) == 0) {
1045 } else if ((b & 0x40) == 0) {
1049 *value = ((b & 0x3f) << 8 | ptr [1]);
1054 *value = ((b & 0x1f) << 24) |
1064 decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
1066 MonoStreamHeader blob = ctx->image->heap_blob;
1067 guint32 value, enc_size;
1069 if (offset >= blob.size)
1072 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1075 if (offset + enc_size + value < offset)
1078 if (offset + enc_size + value > blob.size)
1082 *first_byte = blob.data + offset + enc_size;
1087 safe_read (const char **_ptr, const char *limit, void *dest, int size)
1089 const char *ptr = *_ptr;
1090 if (ptr + size > limit)
1094 *((guint8*)dest) = *((guint8*)ptr);
1098 *((guint16*)dest) = read16 (ptr);
1102 *((guint32*)dest) = read32 (ptr);
1111 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1114 const char *ptr = *_ptr;
1115 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1120 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1121 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1122 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1123 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1126 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1129 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1132 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1134 const char *ptr = *_ptr;
1139 if (!safe_read8 (type, ptr, end))
1140 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1142 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1147 if (!safe_read_cint (token, ptr, end))
1148 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1150 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1151 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1159 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1161 const char *ptr = *_ptr;
1163 guint32 size, num, i;
1165 if (!safe_read8 (val, ptr, end))
1166 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1169 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1171 if (!safe_read_cint (size, ptr, end))
1172 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1174 for (i = 0; i < size; ++i) {
1175 if (!safe_read_cint (num, ptr, end))
1176 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1179 if (!safe_read_cint (size, ptr, end))
1180 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1182 for (i = 0; i < size; ++i) {
1183 if (!safe_read_cint (num, ptr, end))
1184 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1192 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1194 const char *ptr = *_ptr;
1196 guint32 count, token, i;
1198 if (!safe_read8 (type, ptr, end))
1199 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1201 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1202 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1204 if (!safe_read_cint (token, ptr, end))
1205 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1207 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1208 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1210 if (!safe_read_cint (count, ptr, end))
1211 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1214 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1216 for (i = 0; i < count; ++i) {
1217 if (!parse_type (ctx, &ptr, end))
1218 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1225 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1227 const char *ptr = *_ptr;
1231 if (!safe_read8 (type, ptr, end))
1232 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1234 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1235 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1236 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1237 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1238 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1242 if (!parse_custom_mods (ctx, &ptr, end))
1243 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1245 if (!safe_read8 (type, ptr, end))
1246 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1248 if (type != MONO_TYPE_VOID) {
1250 if (!parse_type (ctx, &ptr, end))
1251 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1255 case MONO_TYPE_VALUETYPE:
1256 case MONO_TYPE_CLASS:
1257 if (!safe_read_cint (token, ptr, end))
1258 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1260 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1261 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1265 case MONO_TYPE_MVAR:
1266 if (!safe_read_cint (token, ptr, end))
1267 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1270 case MONO_TYPE_ARRAY:
1271 if (!parse_type (ctx, &ptr, end))
1272 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1273 if (!parse_array_shape (ctx, &ptr, end))
1274 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1277 case MONO_TYPE_GENERICINST:
1278 if (!parse_generic_inst (ctx, &ptr, end))
1279 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1282 case MONO_TYPE_FNPTR:
1283 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1284 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1287 case MONO_TYPE_SZARRAY:
1288 if (!parse_custom_mods (ctx, &ptr, end))
1289 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1290 if (!parse_type (ctx, &ptr, end))
1291 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1299 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1304 if (!parse_custom_mods (ctx, _ptr, end))
1308 if (!safe_read8 (type, ptr, end))
1309 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1311 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1316 //it's a byref, update the cursor ptr
1317 if (type == MONO_TYPE_BYREF)
1320 return parse_type (ctx, _ptr, end);
1324 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1329 if (!parse_custom_mods (ctx, _ptr, end))
1333 if (!safe_read8 (type, ptr, end))
1334 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1336 if (type == MONO_TYPE_TYPEDBYREF) {
1341 //it's a byref, update the cursor ptr
1342 if (type == MONO_TYPE_BYREF)
1345 return parse_type (ctx, _ptr, end);
1349 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1352 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1353 const char *ptr = *_ptr;
1354 gboolean saw_sentinel = FALSE;
1356 if (!safe_read8 (cconv, ptr, end))
1357 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1360 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1362 if (allow_unmanaged) {
1363 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1364 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1365 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1366 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1368 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1369 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1371 if ((cconv & 0x10) && gparam_count == 0)
1372 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1374 if (allow_unmanaged && (cconv & 0x10))
1375 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1377 if (!safe_read_cint (param_count, ptr, end))
1378 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1380 if (!parse_return_type (ctx, &ptr, end))
1381 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1383 for (i = 0; i < param_count; ++i) {
1384 if (allow_sentinel) {
1385 if (!safe_read8 (type, ptr, end))
1386 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1388 if (type == MONO_TYPE_SENTINEL) {
1389 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1390 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1393 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1395 saw_sentinel = TRUE;
1401 if (!parse_param (ctx, &ptr, end))
1402 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1410 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1413 unsigned param_count = 0, i;
1414 const char *ptr = *_ptr;
1416 if (!safe_read8 (sig, ptr, end))
1417 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1419 if (sig != 0x08 && sig != 0x28)
1420 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1422 if (!safe_read_cint (param_count, ptr, end))
1423 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1425 if (!parse_custom_mods (ctx, &ptr, end))
1428 if (!parse_type (ctx, &ptr, end))
1429 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1431 for (i = 0; i < param_count; ++i) {
1432 if (!parse_type (ctx, &ptr, end))
1433 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1441 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1443 const char *ptr = *_ptr;
1444 guint8 signature = 0;
1446 if (!safe_read8 (signature, ptr, end))
1447 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1449 if (signature != 0x06)
1450 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1453 if (!parse_custom_mods (ctx, _ptr, end))
1456 return parse_type (ctx, _ptr, end);
1460 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1463 unsigned locals_count = 0, i;
1464 const char *ptr = *_ptr;
1466 if (!safe_read8 (sig, ptr, end))
1467 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1470 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1472 if (!safe_read_cint (locals_count, ptr, end))
1473 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1475 if (locals_count == 0)
1476 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1478 for (i = 0; i < locals_count; ++i) {
1479 if (!safe_read8 (sig, ptr, end))
1480 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1482 if (sig == MONO_TYPE_TYPEDBYREF)
1485 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1486 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1487 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1488 if (!safe_read8 (sig, ptr, end))
1489 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1492 if (!parse_type (ctx, &ptr, end))
1493 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1501 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1503 int size = 0, signature = 0;
1504 const char *ptr = NULL, *end;
1506 if (!decode_signature_header (ctx, offset, &size, &ptr))
1507 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1510 if (!safe_read8 (signature, ptr, end))
1511 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1514 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1517 return parse_field (ctx, &ptr, end);
1521 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1524 const char *ptr = NULL, *end;
1526 if (!decode_signature_header (ctx, offset, &size, &ptr))
1527 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1530 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1534 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1537 unsigned signature = 0;
1538 const char *ptr = NULL, *end;
1540 if (!decode_signature_header (ctx, offset, &size, &ptr))
1541 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1544 if (!safe_read8 (signature, ptr, end))
1545 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1548 if (signature == 0x06)
1549 return parse_field (ctx, &ptr, end);
1551 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1555 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1557 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1558 //TODO do proper verification
1559 return blob.size >= 1 && blob.size - 1 >= offset;
1563 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1565 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1566 //TODO do proper verification
1567 return blob.size >= 1 && blob.size - 1 >= offset;
1571 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1573 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1574 //TODO do proper verification
1575 return blob.size >= 1 && blob.size - 1 >= offset;
1579 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1582 unsigned signature = 0;
1583 const char *ptr = NULL, *end;
1585 if (!decode_signature_header (ctx, offset, &size, &ptr))
1586 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1589 if (!safe_read8 (signature, ptr, end))
1590 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1593 if (signature == 0x07)
1594 return parse_locals_signature (ctx, &ptr, end);
1595 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1599 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1602 const char *ptr = NULL, *end;
1604 if (!decode_signature_header (ctx, offset, &size, &ptr))
1605 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
1608 return parse_property_signature (ctx, &ptr, end);
1612 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1615 const char *ptr = NULL, *end;
1619 if (!decode_signature_header (ctx, offset, &size, &ptr))
1620 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
1623 if (!parse_custom_mods (ctx, &ptr, end))
1626 if (!safe_read8 (type, ptr, end))
1627 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
1630 if (type == MONO_TYPE_TYPEDBYREF)
1633 return parse_type (ctx, &ptr, end);
1637 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1640 const char *ptr = NULL, *end;
1642 guint32 count = 0, i;
1644 if (!decode_signature_header (ctx, offset, &size, &ptr))
1645 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
1648 if (!safe_read8 (type, ptr, end))
1649 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
1652 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
1654 if (!safe_read_cint (count, ptr, end))
1655 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
1658 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
1660 for (i = 0; i < count; ++i) {
1661 if (!parse_type (ctx, &ptr, end))
1662 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
1668 is_valid_blob_object (VerifyContext *ctx, guint32 offset)
1670 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1671 guint32 entry_size, bytes;
1673 if (blob.size < offset) {
1678 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1681 if (offset + entry_size + bytes < offset)
1684 return blob.size >= offset + entry_size + bytes;
1688 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1690 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1691 guint32 size, entry_size, bytes;
1693 if (blob.size < offset) {
1699 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1702 if (type == MONO_TYPE_STRING) {
1703 //String is encoded as: compressed_int:len len *chars
1706 if (offset > offset + entry_size * 2) //overflow
1708 offset += offset + entry_size * 2;
1709 return offset <= blob.size;
1713 case MONO_TYPE_BOOLEAN:
1718 case MONO_TYPE_CHAR:
1726 case MONO_TYPE_CLASS:
1736 g_assert_not_reached ();
1739 if (size != entry_size)
1743 if(offset > offset + size) //overflow
1746 if (offset + size > blob.size)
1749 if (type == MONO_TYPE_CLASS && read32 (ctx->data + offset))
1755 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1757 //TODO do proper method header validation
1758 return mono_cli_rva_image_map (ctx->image, rva) != INVALID_ADDRESS;
1762 verify_module_table (VerifyContext *ctx)
1764 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1765 guint32 data [MONO_MODULE_SIZE];
1767 if (table->rows != 1)
1768 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1770 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1772 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1773 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1775 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1776 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1778 if (data [MONO_MODULE_ENC] != 0)
1779 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1781 if (data [MONO_MODULE_ENCBASE] != 0)
1782 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1786 verify_typeref_table (VerifyContext *ctx)
1788 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1789 guint32 data [MONO_TYPEREF_SIZE];
1792 for (i = 0; i < table->rows; ++i) {
1793 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1794 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1795 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1797 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1798 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1800 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1801 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1803 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1804 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
1808 /*bits 9,11,14,15,19,21,24-31 */
1809 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
1811 verify_typedef_table (VerifyContext *ctx)
1813 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1814 guint32 data [MONO_TYPEDEF_SIZE];
1815 guint32 fieldlist = 1, methodlist = 1;
1818 if (table->rows == 0)
1819 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
1821 for (i = 0; i < table->rows; ++i) {
1822 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
1823 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
1824 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
1826 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
1827 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
1829 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
1830 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1832 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
1833 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1835 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
1836 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
1838 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1839 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
1842 if (data [MONO_TYPEDEF_EXTENDS] != 0)
1843 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
1845 if (typedef_is_system_object (ctx, data) && data [MONO_TYPEDEF_EXTENDS] != 0)
1846 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
1848 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
1849 if (data [MONO_TYPEDEF_EXTENDS])
1850 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
1851 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
1852 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
1854 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1855 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
1857 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1858 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
1862 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
1863 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
1865 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
1866 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
1868 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
1869 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));
1871 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
1872 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
1874 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
1875 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
1877 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
1878 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));
1881 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
1882 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
1887 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
1889 verify_field_table (VerifyContext *ctx)
1891 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
1892 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
1895 module_field_list = (guint32)-1;
1896 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1897 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1898 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
1901 for (i = 0; i < table->rows; ++i) {
1902 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
1903 flags = data [MONO_FIELD_FLAGS];
1905 if (flags & INVALID_FIELD_FLAG_BITS)
1906 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
1908 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
1909 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
1911 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
1912 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
1914 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
1915 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
1917 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
1918 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
1920 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
1921 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
1922 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
1924 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
1925 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1926 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1928 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
1929 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1930 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
1932 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
1933 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
1934 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1936 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
1937 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
1939 //TODO verify contant flag
1940 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
1941 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
1943 if (i + 1 < module_field_list) {
1944 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
1945 if (!(flags & FIELD_ATTRIBUTE_STATIC))
1946 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
1947 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
1948 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
1953 /*bits 6,8,9,10,11,13,14,15*/
1954 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
1956 verify_method_table (VerifyContext *ctx)
1958 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1959 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
1960 guint32 paramlist = 1;
1961 gboolean is_ctor, is_cctor;
1965 module_method_list = (guint32)-1;
1966 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1967 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1968 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
1971 for (i = 0; i < table->rows; ++i) {
1972 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
1973 rva = data [MONO_METHOD_RVA];
1974 implflags = data [MONO_METHOD_IMPLFLAGS];
1975 flags = data [MONO_METHOD_FLAGS];
1976 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
1977 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
1980 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
1981 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
1984 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
1986 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
1987 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
1989 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
1990 is_ctor = !strcmp (".ctor", name);
1991 is_cctor = !strcmp (".cctor", name);
1993 if ((is_ctor || is_cctor) &&
1994 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
1995 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
1997 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
1998 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2000 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2001 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2002 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2003 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2004 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2007 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2008 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2010 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2011 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2013 //XXX no checks against cas stuff 10,11,12,13)
2015 //TODO check iface with .ctor (15,16)
2017 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2018 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2020 if (i + 1 < module_method_list) {
2021 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2022 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2023 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2024 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2025 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2026 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2029 //TODO check valuetype for synchronized
2031 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2032 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2034 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
2035 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2037 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2038 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2039 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2041 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2042 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2044 //TODO check signature contents
2047 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2048 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2049 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2050 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2051 if (!is_valid_method_header (ctx, rva))
2052 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2054 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2055 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2058 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2060 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2061 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2062 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2064 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2065 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2067 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2068 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2070 if (data [MONO_METHOD_PARAMLIST] == 0)
2071 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2073 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2074 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));
2076 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2077 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2079 paramlist = data [MONO_METHOD_PARAMLIST];
2085 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2087 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2088 guint32 row = *current_method;
2089 guint32 paramlist, tmp;
2092 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2093 while (row < table->rows) {
2094 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2095 if (tmp > paramlist) {
2096 *current_method = row;
2097 return tmp - paramlist;
2102 /*no more methods, all params apply to the last one*/
2103 *current_method = table->rows;
2108 #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))
2110 verify_param_table (VerifyContext *ctx)
2112 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2113 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2114 gboolean first_param = TRUE;
2117 remaining_params = get_next_param_count (ctx, ¤t_method);
2119 for (i = 0; i < table->rows; ++i) {
2120 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2121 flags = data [MONO_PARAM_FLAGS];
2123 if (flags & INVALID_PARAM_FLAGS_BITS)
2124 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2126 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2127 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2128 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2130 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2131 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2134 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)
2135 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2137 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2138 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2140 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2141 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2143 first_param = FALSE;
2144 sequence = data [MONO_PARAM_SEQUENCE];
2145 if (--remaining_params == 0) {
2146 remaining_params = get_next_param_count (ctx, ¤t_method);
2153 verify_interfaceimpl_table (VerifyContext *ctx)
2155 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2156 guint32 data [MONO_INTERFACEIMPL_SIZE];
2159 for (i = 0; i < table->rows; ++i) {
2160 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2161 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2162 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2164 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2165 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2167 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2168 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2173 verify_memberref_table (VerifyContext *ctx)
2175 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2176 guint32 data [MONO_MEMBERREF_SIZE];
2179 for (i = 0; i < table->rows; ++i) {
2180 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2182 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2183 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2185 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2186 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2188 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2189 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2191 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2192 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2197 verify_constant_table (VerifyContext *ctx)
2199 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2200 guint32 data [MONO_CONSTANT_SIZE], type;
2203 for (i = 0; i < table->rows; ++i) {
2204 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2205 type = data [MONO_CONSTANT_TYPE];
2207 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2208 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2210 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2211 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2213 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2214 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2216 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2217 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2222 verify_cattr_table (VerifyContext *ctx)
2224 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2225 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2228 for (i = 0; i < table->rows; ++i) {
2229 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2231 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2232 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2234 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2235 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2237 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2238 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2244 verify_field_marshal_table (VerifyContext *ctx)
2246 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2247 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2250 for (i = 0; i < table->rows; ++i) {
2251 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2253 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2254 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2256 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2257 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2259 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2260 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2262 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2263 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2269 verify_decl_security_table (VerifyContext *ctx)
2271 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2272 guint32 data [MONO_DECL_SECURITY_SIZE];
2275 for (i = 0; i < table->rows; ++i) {
2276 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2278 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2279 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2281 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2282 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2284 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2285 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2287 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2288 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2294 verify_class_layout_table (VerifyContext *ctx)
2296 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2297 guint32 data [MONO_CLASS_LAYOUT_SIZE];
2300 for (i = 0; i < table->rows; ++i) {
2301 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2303 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2304 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2306 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2318 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2324 verify_field_layout_table (VerifyContext *ctx)
2326 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2327 guint32 data [MONO_FIELD_LAYOUT_SIZE];
2330 for (i = 0; i < table->rows; ++i) {
2331 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2333 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2334 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2339 verify_standalonesig_table (VerifyContext *ctx)
2341 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2342 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2345 for (i = 0; i < table->rows; ++i) {
2346 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2348 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2349 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2354 verify_eventmap_table (VerifyContext *ctx)
2356 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2357 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2360 for (i = 0; i < table->rows; ++i) {
2361 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2363 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2364 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2366 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2367 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2369 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2373 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2375 verify_event_table (VerifyContext *ctx)
2377 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2378 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2379 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2380 gboolean found_add, found_remove;
2383 for (i = 0; i < table->rows; ++i) {
2384 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2386 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2387 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2389 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2390 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2392 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2393 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2395 //check for Add and Remove
2396 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2397 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2399 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2401 //first we move to the first row for this event
2403 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2407 //now move forward looking for AddOn and RemoveOn rows
2408 found_add = found_remove = FALSE;
2409 while (idx < sema_table->rows) {
2410 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2411 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2413 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2415 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2416 found_remove = TRUE;
2417 if (found_add && found_remove)
2423 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2425 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2430 verify_propertymap_table (VerifyContext *ctx)
2432 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2433 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2436 for (i = 0; i < table->rows; ++i) {
2437 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2439 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2440 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2442 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2443 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2445 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2449 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2451 verify_property_table (VerifyContext *ctx)
2453 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2454 guint32 data [MONO_PROPERTY_SIZE];
2457 for (i = 0; i < table->rows; ++i) {
2458 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2460 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2461 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2463 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2464 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2466 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2467 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2469 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2470 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2471 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2477 verify_methodimpl_table (VerifyContext *ctx)
2479 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2480 guint32 data [MONO_METHODIMPL_SIZE];
2483 for (i = 0; i < table->rows; ++i) {
2484 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2486 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2487 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2489 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2490 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2492 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2493 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2495 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2496 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2498 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2499 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2504 verify_moduleref_table (VerifyContext *ctx)
2506 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2507 guint32 data [MONO_MODULEREF_SIZE];
2510 for (i = 0; i < table->rows; ++i) {
2511 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2513 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2514 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2519 verify_typespec_table (VerifyContext *ctx)
2521 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2522 guint32 data [MONO_TYPESPEC_SIZE];
2525 for (i = 0; i < table->rows; ++i) {
2526 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2528 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2529 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2533 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10))
2535 verify_implmap_table (VerifyContext *ctx)
2537 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2538 guint32 data [MONO_IMPLMAP_SIZE], cconv;
2541 for (i = 0; i < table->rows; ++i) {
2542 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2544 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2545 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2547 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2548 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2549 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2551 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2552 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2554 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2555 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2557 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2558 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2560 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2561 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2563 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULE].rows + 1)
2564 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2569 verify_fieldrva_table (VerifyContext *ctx)
2571 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2572 guint32 data [MONO_FIELD_RVA_SIZE];
2575 for (i = 0; i < table->rows; ++i) {
2576 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2578 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2579 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2581 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2582 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2586 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
2588 verify_assembly_table (VerifyContext *ctx)
2590 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2591 guint32 data [MONO_ASSEMBLY_SIZE], hash;
2594 if (table->rows > 1)
2595 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2597 for (i = 0; i < table->rows; ++i) {
2598 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2600 hash = data [MONO_ASSEMBLY_HASH_ALG];
2601 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2602 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2604 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2605 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2607 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY]))
2608 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2610 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2611 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2613 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2614 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2618 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2620 verify_assemblyref_table (VerifyContext *ctx)
2622 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2623 guint32 data [MONO_ASSEMBLYREF_SIZE];
2626 for (i = 0; i < table->rows; ++i) {
2627 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2629 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2630 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2632 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY]))
2633 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2635 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2636 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
2638 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
2639 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
2641 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE]))
2642 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
2646 #define INVALID_FILE_FLAGS_BITS ~(1)
2648 verify_file_table (VerifyContext *ctx)
2650 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
2651 guint32 data [MONO_FILE_SIZE];
2654 for (i = 0; i < table->rows; ++i) {
2655 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
2657 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
2658 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
2660 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
2661 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
2663 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE]))
2664 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
2668 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
2670 verify_exportedtype_table (VerifyContext *ctx)
2672 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
2673 guint32 data [MONO_EXP_TYPE_SIZE];
2676 for (i = 0; i < table->rows; ++i) {
2677 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
2679 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
2680 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
2682 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
2683 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
2685 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
2686 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
2688 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2689 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
2691 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2692 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
2694 /*nested type can't have a namespace*/
2695 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
2696 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
2700 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
2702 verify_manifest_resource_table (VerifyContext *ctx)
2704 MonoCLIImageInfo *iinfo = ctx->image->image_info;
2705 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2706 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
2707 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
2710 resources_size = ch->ch_resources.size;
2712 for (i = 0; i < table->rows; ++i) {
2713 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
2715 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
2716 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
2718 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
2719 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
2721 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
2722 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
2724 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
2725 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
2727 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2728 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2730 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
2731 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])));
2733 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
2734 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
2736 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
2737 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
2742 verify_nested_class_table (VerifyContext *ctx)
2744 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
2745 guint32 data [MONO_NESTED_CLASS_SIZE];
2748 for (i = 0; i < table->rows; ++i) {
2749 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
2751 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2752 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
2753 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2754 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2755 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
2756 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2760 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
2762 verify_generic_param_table (VerifyContext *ctx)
2764 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
2765 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
2766 int i, param_number = 0;
2768 for (i = 0; i < table->rows; ++i) {
2769 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
2771 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
2772 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
2774 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
2775 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
2777 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
2778 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
2780 token = data [MONO_GENERICPARAM_OWNER];
2782 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
2783 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
2785 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
2786 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
2788 if (token != last_token) {
2793 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
2794 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));
2801 verify_method_spec_table (VerifyContext *ctx)
2803 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
2804 guint32 data [MONO_METHODSPEC_SIZE];
2807 for (i = 0; i < table->rows; ++i) {
2808 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
2810 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2811 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
2813 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2814 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
2816 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
2817 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
2822 verify_generic_param_constraint_table (VerifyContext *ctx)
2824 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
2825 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
2828 for (i = 0; i < table->rows; ++i) {
2829 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
2831 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
2832 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
2834 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2835 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
2837 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2838 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
2843 verify_tables_data (VerifyContext *ctx)
2845 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
2846 guint32 size = 0, tables_offset;
2849 for (i = 0; i < 0x2D; ++i) {
2850 MonoTableInfo *table = &ctx->image->tables [i];
2852 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
2853 if (tmp_size < size) {
2861 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
2863 tables_offset = ctx->image->tables_base - ctx->data;
2864 if (!bounds_check_offset (&tables_area, tables_offset, size))
2865 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)));
2867 verify_module_table (ctx);
2869 verify_typeref_table (ctx);
2871 verify_typedef_table (ctx);
2873 verify_field_table (ctx);
2875 verify_method_table (ctx);
2877 verify_param_table (ctx);
2879 verify_interfaceimpl_table (ctx);
2881 verify_memberref_table (ctx);
2883 verify_constant_table (ctx);
2885 verify_cattr_table (ctx);
2887 verify_field_marshal_table (ctx);
2889 verify_decl_security_table (ctx);
2891 verify_class_layout_table (ctx);
2893 verify_field_layout_table (ctx);
2895 verify_standalonesig_table (ctx);
2897 verify_eventmap_table (ctx);
2899 verify_event_table (ctx);
2901 verify_propertymap_table (ctx);
2903 verify_property_table (ctx);
2905 verify_methodimpl_table (ctx);
2907 verify_moduleref_table (ctx);
2909 verify_typespec_table (ctx);
2911 verify_implmap_table (ctx);
2913 verify_fieldrva_table (ctx);
2915 verify_assembly_table (ctx);
2917 verify_assemblyref_table (ctx);
2919 verify_file_table (ctx);
2921 verify_exportedtype_table (ctx);
2923 verify_manifest_resource_table (ctx);
2925 verify_nested_class_table (ctx);
2927 verify_generic_param_table (ctx);
2929 verify_method_spec_table (ctx);
2931 verify_generic_param_constraint_table (ctx);
2935 mono_verifier_is_corlib (MonoImage *image)
2937 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
2938 TRUE : mono_security_core_clr_is_platform_image (image);
2940 return trusted_location && !strcmp ("mscorlib.dll", image->name);
2944 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
2946 memset (ctx, 0, sizeof (VerifyContext));
2948 ctx->report_error = error_list != NULL;
2950 ctx->size = image->raw_data_len;
2951 ctx->data = image->raw_data;
2952 ctx->is_corlib = mono_verifier_is_corlib (image);
2956 cleanup_context (VerifyContext *ctx, GSList **error_list)
2958 g_free (ctx->sections);
2960 *error_list = ctx->errors;
2962 mono_free_verify_list (ctx->errors);
2967 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2971 if (!mono_verifier_is_enabled_for_image (image))
2974 init_verify_context (&ctx, image, error_list);
2975 ctx.stage = STAGE_PE;
2977 verify_msdos_header (&ctx);
2979 verify_pe_header (&ctx);
2981 verify_pe_optional_header (&ctx);
2983 load_section_table (&ctx);
2985 load_data_directories (&ctx);
2987 verify_import_table (&ctx);
2989 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
2990 verify_resources_table (&ctx);
2993 return cleanup_context (&ctx, error_list);
2997 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3001 if (!mono_verifier_is_enabled_for_image (image))
3004 init_verify_context (&ctx, image, error_list);
3005 ctx.stage = STAGE_CLI;
3007 verify_cli_header (&ctx);
3009 verify_metadata_header (&ctx);
3011 verify_tables_schema (&ctx);
3014 return cleanup_context (&ctx, error_list);
3018 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3022 if (!mono_verifier_is_enabled_for_image (image))
3025 init_verify_context (&ctx, image, error_list);
3026 ctx.stage = STAGE_TABLES;
3028 verify_tables_data (&ctx);
3030 return cleanup_context (&ctx, error_list);
3034 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3040 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3046 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3050 #endif /* DISABLE_VERIFIER */