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_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1131 const char *ptr = *_ptr;
1136 if (!safe_read8 (type, ptr, end))
1137 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1139 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1144 if (!safe_read_cint (token, ptr, end))
1145 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1147 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1148 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1156 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1158 const char *ptr = *_ptr;
1160 guint32 size, num, i;
1162 if (!safe_read8 (val, ptr, end))
1163 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1166 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1168 if (!safe_read_cint (size, ptr, end))
1169 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1171 for (i = 0; i < size; ++i) {
1172 if (!safe_read_cint (num, ptr, end))
1173 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1176 if (!safe_read_cint (size, ptr, end))
1177 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1179 for (i = 0; i < size; ++i) {
1180 if (!safe_read_cint (num, ptr, end))
1181 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1189 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1191 const char *ptr = *_ptr;
1193 guint32 count, token, i;
1195 if (!safe_read8 (type, ptr, end))
1196 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1198 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1199 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1201 if (!safe_read_cint (token, ptr, end))
1202 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1204 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1205 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1207 if (!safe_read_cint (count, ptr, end))
1208 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1211 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1213 for (i = 0; i < count; ++i) {
1214 if (!parse_type (ctx, &ptr, end))
1215 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1222 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1224 const char *ptr = *_ptr;
1228 if (!safe_read8 (type, ptr, end))
1229 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1231 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1232 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1233 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1234 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1235 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1239 if (!parse_custom_mods (ctx, &ptr, end))
1240 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1242 if (!safe_read8 (type, ptr, end))
1243 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1245 if (type != MONO_TYPE_VOID) {
1247 if (!parse_type (ctx, &ptr, end))
1248 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1252 case MONO_TYPE_VALUETYPE:
1253 case MONO_TYPE_CLASS:
1254 if (!safe_read_cint (token, ptr, end))
1255 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1257 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1258 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1262 case MONO_TYPE_MVAR:
1263 if (!safe_read_cint (token, ptr, end))
1264 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1267 case MONO_TYPE_ARRAY:
1268 if (!parse_type (ctx, &ptr, end))
1269 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1270 if (!parse_array_shape (ctx, &ptr, end))
1271 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1274 case MONO_TYPE_GENERICINST:
1275 if (!parse_generic_inst (ctx, &ptr, end))
1276 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1284 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1289 if (!parse_custom_mods (ctx, _ptr, end))
1293 if (!safe_read8 (type, ptr, end))
1294 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1296 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1301 //it's a byref, update the cursor ptr
1302 if (type == MONO_TYPE_BYREF)
1305 return parse_type (ctx, _ptr, end);
1309 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1314 if (!parse_custom_mods (ctx, _ptr, end))
1318 if (!safe_read8 (type, ptr, end))
1319 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1321 if (type == MONO_TYPE_TYPEDBYREF) {
1326 //it's a byref, update the cursor ptr
1327 if (type == MONO_TYPE_BYREF)
1330 return parse_type (ctx, _ptr, end);
1334 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1337 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1338 const char *ptr = *_ptr;
1339 gboolean saw_sentinel = FALSE;
1341 if (!safe_read8 (cconv, ptr, end))
1342 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1345 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1347 if (allow_unmanaged) {
1348 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1349 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1350 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1351 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1353 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1354 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1356 if ((cconv & 0x10) && gparam_count == 0)
1357 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1359 if (allow_unmanaged && (cconv & 0x10))
1360 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1362 if (!safe_read_cint (param_count, ptr, end))
1363 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1365 if (!parse_return_type (ctx, &ptr, end))
1366 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1368 for (i = 0; i < param_count; ++i) {
1369 if (allow_sentinel) {
1370 if (!safe_read8 (type, ptr, end))
1371 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1373 if (type == MONO_TYPE_SENTINEL) {
1374 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1375 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1378 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1380 saw_sentinel = TRUE;
1386 if (!parse_param (ctx, &ptr, end))
1387 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1395 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1398 unsigned param_count = 0, i;
1399 const char *ptr = *_ptr;
1401 if (!safe_read8 (sig, ptr, end))
1402 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1404 if (sig != 0x08 && sig != 0x28)
1405 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1407 if (!safe_read_cint (param_count, ptr, end))
1408 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1410 if (!parse_custom_mods (ctx, &ptr, end))
1413 if (!parse_type (ctx, &ptr, end))
1414 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1416 for (i = 0; i < param_count; ++i) {
1417 if (!parse_type (ctx, &ptr, end))
1418 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1426 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1428 const char *ptr = *_ptr;
1429 guint8 signature = 0;
1431 if (!safe_read8 (signature, ptr, end))
1432 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1434 if (signature != 0x06)
1435 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1438 if (!parse_custom_mods (ctx, _ptr, end))
1441 return parse_type (ctx, _ptr, end);
1445 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1448 unsigned locals_count = 0, i;
1449 const char *ptr = *_ptr;
1451 if (!safe_read8 (sig, ptr, end))
1452 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1455 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1457 if (!safe_read_cint (locals_count, ptr, end))
1458 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1460 if (locals_count == 0)
1461 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1463 for (i = 0; i < locals_count; ++i) {
1464 if (!safe_read8 (sig, ptr, end))
1465 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1467 if (sig == MONO_TYPE_TYPEDBYREF)
1470 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1471 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1472 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1473 if (!safe_read8 (sig, ptr, end))
1474 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1477 if (!parse_type (ctx, &ptr, end))
1478 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1486 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1488 int size = 0, signature = 0;
1489 const char *ptr = NULL, *end;
1491 if (!decode_signature_header (ctx, offset, &size, &ptr))
1492 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1495 if (!safe_read8 (signature, ptr, end))
1496 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1499 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1502 return parse_field (ctx, &ptr, end);
1506 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1509 const char *ptr = NULL, *end;
1511 if (!decode_signature_header (ctx, offset, &size, &ptr))
1512 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1515 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1519 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1522 unsigned signature = 0;
1523 const char *ptr = NULL, *end;
1525 if (!decode_signature_header (ctx, offset, &size, &ptr))
1526 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1529 if (!safe_read8 (signature, ptr, end))
1530 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1533 if (signature == 0x06)
1534 return parse_field (ctx, &ptr, end);
1536 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1540 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1542 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1543 //TODO do proper verification
1544 return blob.size >= 1 && blob.size - 1 >= offset;
1548 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1550 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1551 //TODO do proper verification
1552 return blob.size >= 1 && blob.size - 1 >= offset;
1556 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1558 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1559 //TODO do proper verification
1560 return blob.size >= 1 && blob.size - 1 >= offset;
1564 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1567 unsigned signature = 0;
1568 const char *ptr = NULL, *end;
1570 if (!decode_signature_header (ctx, offset, &size, &ptr))
1571 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1574 if (!safe_read8 (signature, ptr, end))
1575 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1578 if (signature == 0x07)
1579 return parse_locals_signature (ctx, &ptr, end);
1580 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1584 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1587 const char *ptr = NULL, *end;
1589 if (!decode_signature_header (ctx, offset, &size, &ptr))
1590 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
1593 return parse_property_signature (ctx, &ptr, end);
1597 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1599 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1600 //TODO do proper verification
1601 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1605 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1607 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1608 //TODO do proper verification
1609 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1613 is_valid_blob_object (VerifyContext *ctx, guint32 offset)
1615 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1616 guint32 entry_size, bytes;
1618 if (blob.size < offset) {
1623 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1626 if (offset + entry_size + bytes < offset)
1629 return blob.size >= offset + entry_size + bytes;
1633 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1635 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1636 guint32 size, entry_size, bytes;
1638 if (blob.size < offset) {
1644 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1647 if (type == MONO_TYPE_STRING) {
1648 //String is encoded as: compressed_int:len len *chars
1651 if (offset > offset + entry_size * 2) //overflow
1653 offset += offset + entry_size * 2;
1654 return offset <= blob.size;
1658 case MONO_TYPE_BOOLEAN:
1663 case MONO_TYPE_CHAR:
1671 case MONO_TYPE_CLASS:
1681 g_assert_not_reached ();
1684 if (size != entry_size)
1688 if(offset > offset + size) //overflow
1691 if (offset + size > blob.size)
1694 if (type == MONO_TYPE_CLASS && read32 (ctx->data + offset))
1700 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1702 //TODO do proper method header validation
1703 return mono_cli_rva_image_map (ctx->image, rva) != INVALID_ADDRESS;
1707 verify_module_table (VerifyContext *ctx)
1709 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1710 guint32 data [MONO_MODULE_SIZE];
1712 if (table->rows != 1)
1713 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1715 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1717 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1718 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1720 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1721 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1723 if (data [MONO_MODULE_ENC] != 0)
1724 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1726 if (data [MONO_MODULE_ENCBASE] != 0)
1727 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1731 verify_typeref_table (VerifyContext *ctx)
1733 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1734 guint32 data [MONO_TYPEREF_SIZE];
1737 for (i = 0; i < table->rows; ++i) {
1738 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1739 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1740 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1742 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1743 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1745 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1746 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1748 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1749 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
1753 /*bits 9,11,14,15,19,21,24-31 */
1754 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
1756 verify_typedef_table (VerifyContext *ctx)
1758 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1759 guint32 data [MONO_TYPEDEF_SIZE];
1760 guint32 fieldlist = 1, methodlist = 1;
1763 if (table->rows == 0)
1764 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
1766 for (i = 0; i < table->rows; ++i) {
1767 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
1768 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
1769 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
1771 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
1772 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
1774 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
1775 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1777 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
1778 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1780 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
1781 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
1783 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1784 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
1787 if (data [MONO_TYPEDEF_EXTENDS] != 0)
1788 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
1790 if (typedef_is_system_object (ctx, data) && data [MONO_TYPEDEF_EXTENDS] != 0)
1791 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
1793 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
1794 if (data [MONO_TYPEDEF_EXTENDS])
1795 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
1796 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
1797 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
1799 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1800 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
1802 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1803 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
1807 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
1808 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
1810 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
1811 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
1813 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
1814 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));
1816 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
1817 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
1819 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
1820 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
1822 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
1823 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));
1826 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
1827 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
1832 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
1834 verify_field_table (VerifyContext *ctx)
1836 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
1837 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
1840 module_field_list = (guint32)-1;
1841 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1842 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1843 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
1846 for (i = 0; i < table->rows; ++i) {
1847 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
1848 flags = data [MONO_FIELD_FLAGS];
1850 if (flags & INVALID_FIELD_FLAG_BITS)
1851 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
1853 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
1854 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
1856 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
1857 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
1859 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
1860 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
1862 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
1863 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
1865 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
1866 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
1867 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
1869 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
1870 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1871 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1873 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
1874 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1875 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
1877 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
1878 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
1879 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1881 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
1882 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
1884 //TODO verify contant flag
1885 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
1886 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
1888 if (i + 1 < module_field_list) {
1889 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
1890 if (!(flags & FIELD_ATTRIBUTE_STATIC))
1891 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
1892 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
1893 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
1898 /*bits 6,8,9,10,11,13,14,15*/
1899 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
1901 verify_method_table (VerifyContext *ctx)
1903 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1904 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
1905 guint32 paramlist = 1;
1906 gboolean is_ctor, is_cctor;
1910 module_method_list = (guint32)-1;
1911 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1912 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1913 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
1916 for (i = 0; i < table->rows; ++i) {
1917 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
1918 rva = data [MONO_METHOD_RVA];
1919 implflags = data [MONO_METHOD_IMPLFLAGS];
1920 flags = data [MONO_METHOD_FLAGS];
1921 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
1922 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
1925 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
1926 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
1929 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
1931 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
1932 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
1934 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
1935 is_ctor = !strcmp (".ctor", name);
1936 is_cctor = !strcmp (".cctor", name);
1938 if ((is_ctor || is_cctor) &&
1939 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
1940 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
1942 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
1943 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
1945 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
1946 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1947 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
1948 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
1949 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
1952 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
1953 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
1955 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
1956 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
1958 //XXX no checks against cas stuff 10,11,12,13)
1960 //TODO check iface with .ctor (15,16)
1962 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
1963 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
1965 if (i + 1 < module_method_list) {
1966 if (!(flags & METHOD_ATTRIBUTE_STATIC))
1967 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
1968 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
1969 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
1970 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
1971 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
1974 //TODO check valuetype for synchronized
1976 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
1977 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
1979 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
1980 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
1982 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
1983 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1984 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
1986 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
1987 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
1989 //TODO check signature contents
1992 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
1993 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
1994 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
1995 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
1996 if (!is_valid_method_header (ctx, rva))
1997 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
1999 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2000 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2003 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2005 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2006 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2007 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2009 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2010 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2012 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2013 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2015 if (data [MONO_METHOD_PARAMLIST] == 0)
2016 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2018 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2019 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));
2021 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2022 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2024 paramlist = data [MONO_METHOD_PARAMLIST];
2030 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2032 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2033 guint32 row = *current_method;
2034 guint32 paramlist, tmp;
2037 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2038 while (row < table->rows) {
2039 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2040 if (tmp > paramlist) {
2041 *current_method = row;
2042 return tmp - paramlist;
2047 /*no more methods, all params apply to the last one*/
2048 *current_method = table->rows;
2053 #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))
2055 verify_param_table (VerifyContext *ctx)
2057 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2058 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2059 gboolean first_param = TRUE;
2062 remaining_params = get_next_param_count (ctx, ¤t_method);
2064 for (i = 0; i < table->rows; ++i) {
2065 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2066 flags = data [MONO_PARAM_FLAGS];
2068 if (flags & INVALID_PARAM_FLAGS_BITS)
2069 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2071 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2072 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2073 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2075 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2076 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2079 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)
2080 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2082 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2083 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2085 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2086 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2088 first_param = FALSE;
2089 sequence = data [MONO_PARAM_SEQUENCE];
2090 if (--remaining_params == 0) {
2091 remaining_params = get_next_param_count (ctx, ¤t_method);
2098 verify_interfaceimpl_table (VerifyContext *ctx)
2100 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2101 guint32 data [MONO_INTERFACEIMPL_SIZE];
2104 for (i = 0; i < table->rows; ++i) {
2105 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2106 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2107 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2109 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2110 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2112 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2113 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2118 verify_memberref_table (VerifyContext *ctx)
2120 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2121 guint32 data [MONO_MEMBERREF_SIZE];
2124 for (i = 0; i < table->rows; ++i) {
2125 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2127 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2128 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2130 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2131 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2133 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2134 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2136 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2137 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2142 verify_constant_table (VerifyContext *ctx)
2144 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2145 guint32 data [MONO_CONSTANT_SIZE], type;
2148 for (i = 0; i < table->rows; ++i) {
2149 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2150 type = data [MONO_CONSTANT_TYPE];
2152 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2153 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2155 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2156 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2158 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2159 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2161 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2162 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2167 verify_cattr_table (VerifyContext *ctx)
2169 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2170 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2173 for (i = 0; i < table->rows; ++i) {
2174 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2176 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2177 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2179 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2180 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2182 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2183 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2189 verify_field_marshal_table (VerifyContext *ctx)
2191 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2192 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2195 for (i = 0; i < table->rows; ++i) {
2196 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2198 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2199 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2201 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2202 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2204 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2205 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2207 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2208 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2214 verify_decl_security_table (VerifyContext *ctx)
2216 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2217 guint32 data [MONO_DECL_SECURITY_SIZE];
2220 for (i = 0; i < table->rows; ++i) {
2221 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2223 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2224 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2226 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2227 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2229 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2230 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2232 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2233 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2239 verify_class_layout_table (VerifyContext *ctx)
2241 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2242 guint32 data [MONO_CLASS_LAYOUT_SIZE];
2245 for (i = 0; i < table->rows; ++i) {
2246 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2248 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2249 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2251 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2263 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2269 verify_field_layout_table (VerifyContext *ctx)
2271 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2272 guint32 data [MONO_FIELD_LAYOUT_SIZE];
2275 for (i = 0; i < table->rows; ++i) {
2276 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2278 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2279 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2284 verify_standalonesig_table (VerifyContext *ctx)
2286 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2287 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2290 for (i = 0; i < table->rows; ++i) {
2291 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2293 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2294 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2299 verify_eventmap_table (VerifyContext *ctx)
2301 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2302 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2305 for (i = 0; i < table->rows; ++i) {
2306 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2308 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2309 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2311 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2312 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2314 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2318 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2320 verify_event_table (VerifyContext *ctx)
2322 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2323 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2324 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2325 gboolean found_add, found_remove;
2328 for (i = 0; i < table->rows; ++i) {
2329 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2331 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2332 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2334 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2335 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2337 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2338 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2340 //check for Add and Remove
2341 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2342 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2344 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2346 //first we move to the first row for this event
2348 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2352 //now move forward looking for AddOn and RemoveOn rows
2353 found_add = found_remove = FALSE;
2354 while (idx < sema_table->rows) {
2355 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2356 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2358 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2360 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2361 found_remove = TRUE;
2362 if (found_add && found_remove)
2368 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2370 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2375 verify_propertymap_table (VerifyContext *ctx)
2377 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2378 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2381 for (i = 0; i < table->rows; ++i) {
2382 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2384 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2385 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2387 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2388 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2390 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2394 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2396 verify_property_table (VerifyContext *ctx)
2398 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2399 guint32 data [MONO_PROPERTY_SIZE];
2402 for (i = 0; i < table->rows; ++i) {
2403 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2405 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2406 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2408 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2409 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2411 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2412 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2414 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2415 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2416 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2422 verify_methodimpl_table (VerifyContext *ctx)
2424 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2425 guint32 data [MONO_METHODIMPL_SIZE];
2428 for (i = 0; i < table->rows; ++i) {
2429 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2431 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2432 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2434 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2435 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2437 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2438 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2440 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2441 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2443 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2444 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2449 verify_moduleref_table (VerifyContext *ctx)
2451 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2452 guint32 data [MONO_MODULEREF_SIZE];
2455 for (i = 0; i < table->rows; ++i) {
2456 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2458 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2459 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2464 verify_typespec_table (VerifyContext *ctx)
2466 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2467 guint32 data [MONO_TYPESPEC_SIZE];
2470 for (i = 0; i < table->rows; ++i) {
2471 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2473 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2474 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2478 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10))
2480 verify_implmap_table (VerifyContext *ctx)
2482 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2483 guint32 data [MONO_IMPLMAP_SIZE], cconv;
2486 for (i = 0; i < table->rows; ++i) {
2487 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2489 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2490 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2492 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2493 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2494 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2496 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2497 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2499 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2500 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2502 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2503 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2505 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2506 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2508 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULE].rows + 1)
2509 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2514 verify_fieldrva_table (VerifyContext *ctx)
2516 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2517 guint32 data [MONO_FIELD_RVA_SIZE];
2520 for (i = 0; i < table->rows; ++i) {
2521 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2523 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2524 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2526 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2527 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2531 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
2533 verify_assembly_table (VerifyContext *ctx)
2535 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2536 guint32 data [MONO_ASSEMBLY_SIZE], hash;
2539 if (table->rows > 1)
2540 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2542 for (i = 0; i < table->rows; ++i) {
2543 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2545 hash = data [MONO_ASSEMBLY_HASH_ALG];
2546 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2547 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2549 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2550 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2552 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY]))
2553 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2555 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2556 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2558 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2559 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2563 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2565 verify_assemblyref_table (VerifyContext *ctx)
2567 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2568 guint32 data [MONO_ASSEMBLYREF_SIZE];
2571 for (i = 0; i < table->rows; ++i) {
2572 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2574 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2575 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2577 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY]))
2578 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2580 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2581 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
2583 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
2584 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
2586 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE]))
2587 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
2591 #define INVALID_FILE_FLAGS_BITS ~(1)
2593 verify_file_table (VerifyContext *ctx)
2595 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
2596 guint32 data [MONO_FILE_SIZE];
2599 for (i = 0; i < table->rows; ++i) {
2600 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
2602 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
2603 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
2605 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
2606 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
2608 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE]))
2609 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
2613 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
2615 verify_exportedtype_table (VerifyContext *ctx)
2617 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
2618 guint32 data [MONO_EXP_TYPE_SIZE];
2621 for (i = 0; i < table->rows; ++i) {
2622 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
2624 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
2625 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
2627 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
2628 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
2630 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
2631 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
2633 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2634 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
2636 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2637 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
2639 /*nested type can't have a namespace*/
2640 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
2641 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
2645 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
2647 verify_manifest_resource_table (VerifyContext *ctx)
2649 MonoCLIImageInfo *iinfo = ctx->image->image_info;
2650 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2651 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
2652 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
2655 resources_size = ch->ch_resources.size;
2657 for (i = 0; i < table->rows; ++i) {
2658 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
2660 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
2661 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
2663 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
2664 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
2666 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
2667 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
2669 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
2670 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
2672 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2673 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2675 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
2676 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])));
2678 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
2679 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
2681 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
2682 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
2687 verify_nested_class_table (VerifyContext *ctx)
2689 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
2690 guint32 data [MONO_NESTED_CLASS_SIZE];
2693 for (i = 0; i < table->rows; ++i) {
2694 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
2696 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2697 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
2698 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2699 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2700 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
2701 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2705 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
2707 verify_generic_param_table (VerifyContext *ctx)
2709 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
2710 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
2711 int i, param_number = 0;
2713 for (i = 0; i < table->rows; ++i) {
2714 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
2716 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
2717 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
2719 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
2720 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
2722 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
2723 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
2725 token = data [MONO_GENERICPARAM_OWNER];
2727 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
2728 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
2730 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
2731 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
2733 if (token != last_token) {
2738 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
2739 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));
2746 verify_method_spec_table (VerifyContext *ctx)
2748 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
2749 guint32 data [MONO_METHODSPEC_SIZE];
2752 for (i = 0; i < table->rows; ++i) {
2753 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
2755 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2756 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
2758 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2759 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
2761 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
2762 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
2767 verify_generic_param_constraint_table (VerifyContext *ctx)
2769 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
2770 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
2773 for (i = 0; i < table->rows; ++i) {
2774 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
2776 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
2777 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
2779 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2780 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
2782 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2783 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
2788 verify_tables_data (VerifyContext *ctx)
2790 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
2791 guint32 size = 0, tables_offset;
2794 for (i = 0; i < 0x2D; ++i) {
2795 MonoTableInfo *table = &ctx->image->tables [i];
2797 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
2798 if (tmp_size < size) {
2806 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
2808 tables_offset = ctx->image->tables_base - ctx->data;
2809 if (!bounds_check_offset (&tables_area, tables_offset, size))
2810 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)));
2812 verify_module_table (ctx);
2814 verify_typeref_table (ctx);
2816 verify_typedef_table (ctx);
2818 verify_field_table (ctx);
2820 verify_method_table (ctx);
2822 verify_param_table (ctx);
2824 verify_interfaceimpl_table (ctx);
2826 verify_memberref_table (ctx);
2828 verify_constant_table (ctx);
2830 verify_cattr_table (ctx);
2832 verify_field_marshal_table (ctx);
2834 verify_decl_security_table (ctx);
2836 verify_class_layout_table (ctx);
2838 verify_field_layout_table (ctx);
2840 verify_standalonesig_table (ctx);
2842 verify_eventmap_table (ctx);
2844 verify_event_table (ctx);
2846 verify_propertymap_table (ctx);
2848 verify_property_table (ctx);
2850 verify_methodimpl_table (ctx);
2852 verify_moduleref_table (ctx);
2854 verify_typespec_table (ctx);
2856 verify_implmap_table (ctx);
2858 verify_fieldrva_table (ctx);
2860 verify_assembly_table (ctx);
2862 verify_assemblyref_table (ctx);
2864 verify_file_table (ctx);
2866 verify_exportedtype_table (ctx);
2868 verify_manifest_resource_table (ctx);
2870 verify_nested_class_table (ctx);
2872 verify_generic_param_table (ctx);
2874 verify_method_spec_table (ctx);
2876 verify_generic_param_constraint_table (ctx);
2880 mono_verifier_is_corlib (MonoImage *image)
2882 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
2883 TRUE : mono_security_core_clr_is_platform_image (image);
2885 return trusted_location && !strcmp ("mscorlib.dll", image->name);
2889 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
2891 memset (ctx, 0, sizeof (VerifyContext));
2893 ctx->report_error = error_list != NULL;
2895 ctx->size = image->raw_data_len;
2896 ctx->data = image->raw_data;
2897 ctx->is_corlib = mono_verifier_is_corlib (image);
2901 cleanup_context (VerifyContext *ctx, GSList **error_list)
2903 g_free (ctx->sections);
2905 *error_list = ctx->errors;
2907 mono_free_verify_list (ctx->errors);
2912 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2916 if (!mono_verifier_is_enabled_for_image (image))
2919 init_verify_context (&ctx, image, error_list);
2920 ctx.stage = STAGE_PE;
2922 verify_msdos_header (&ctx);
2924 verify_pe_header (&ctx);
2926 verify_pe_optional_header (&ctx);
2928 load_section_table (&ctx);
2930 load_data_directories (&ctx);
2932 verify_import_table (&ctx);
2934 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
2935 verify_resources_table (&ctx);
2938 return cleanup_context (&ctx, error_list);
2942 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2946 if (!mono_verifier_is_enabled_for_image (image))
2949 init_verify_context (&ctx, image, error_list);
2950 ctx.stage = STAGE_CLI;
2952 verify_cli_header (&ctx);
2954 verify_metadata_header (&ctx);
2956 verify_tables_schema (&ctx);
2959 return cleanup_context (&ctx, error_list);
2963 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2967 if (!mono_verifier_is_enabled_for_image (image))
2970 init_verify_context (&ctx, image, error_list);
2971 ctx.stage = STAGE_TABLES;
2973 verify_tables_data (&ctx);
2975 return cleanup_context (&ctx, error_list);
2979 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2985 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2991 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2995 #endif /* DISABLE_VERIFIER */