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_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1128 const char *ptr = *_ptr;
1133 if (!safe_read8 (type, ptr, end))
1134 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1136 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1141 if (!safe_read_cint (token, ptr, end))
1142 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1144 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1145 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1153 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1155 const char *ptr = *_ptr;
1157 guint32 size, num, i;
1159 if (!safe_read8 (val, ptr, end))
1160 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1163 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1165 if (!safe_read_cint (size, ptr, end))
1166 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1168 for (i = 0; i < size; ++i) {
1169 if (!safe_read_cint (num, ptr, end))
1170 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1173 if (!safe_read_cint (size, ptr, end))
1174 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1176 for (i = 0; i < size; ++i) {
1177 if (!safe_read_cint (num, ptr, end))
1178 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1187 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1189 const char *ptr = *_ptr;
1193 if (!safe_read8 (type, ptr, end))
1194 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1196 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1197 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1198 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1199 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1200 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1204 if (!parse_custom_mods (ctx, &ptr, end))
1205 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1207 if (!safe_read8 (type, ptr, end))
1208 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1210 if (type != MONO_TYPE_VOID) {
1212 if (!parse_type (ctx, &ptr, end))
1213 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1217 case MONO_TYPE_VALUETYPE:
1218 case MONO_TYPE_CLASS:
1219 if (!safe_read_cint (token, ptr, end))
1220 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1222 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1223 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1227 case MONO_TYPE_MVAR:
1228 if (!safe_read_cint (token, ptr, end))
1229 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1231 case MONO_TYPE_ARRAY:
1232 if (!parse_type (ctx, &ptr, end))
1233 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1234 if (!parse_array_shape (ctx, &ptr, end))
1235 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1243 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1248 if (!parse_custom_mods (ctx, _ptr, end))
1252 if (!safe_read8 (type, ptr, end))
1253 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1255 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1260 //it's a byref, update the cursor ptr
1261 if (type == MONO_TYPE_BYREF)
1264 return parse_type (ctx, _ptr, end);
1268 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1273 if (!parse_custom_mods (ctx, _ptr, end))
1277 if (!safe_read8 (type, ptr, end))
1278 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1280 if (type == MONO_TYPE_TYPEDBYREF) {
1285 //it's a byref, update the cursor ptr
1286 if (type == MONO_TYPE_BYREF)
1289 return parse_type (ctx, _ptr, end);
1293 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1296 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1297 const char *ptr = *_ptr;
1298 gboolean saw_sentinel = FALSE;
1300 if (!safe_read8 (cconv, ptr, end))
1301 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1304 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1306 if (allow_unmanaged) {
1307 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1308 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1309 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1310 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1312 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1313 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1315 if ((cconv & 0x10) && gparam_count == 0)
1316 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1318 if (allow_unmanaged && (cconv & 0x10))
1319 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1321 if (!safe_read_cint (param_count, ptr, end))
1322 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1324 if (!parse_return_type (ctx, &ptr, end))
1325 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1327 for (i = 0; i < param_count; ++i) {
1328 if (allow_sentinel) {
1329 if (!safe_read8 (type, ptr, end))
1330 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1332 if (type == MONO_TYPE_SENTINEL) {
1333 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1334 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1337 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1339 saw_sentinel = TRUE;
1345 if (!parse_param (ctx, &ptr, end))
1346 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1354 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1357 unsigned param_count = 0, i;
1358 const char *ptr = *_ptr;
1360 if (!safe_read8 (sig, ptr, end))
1361 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1363 if (sig != 0x08 && sig != 0x28)
1364 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1366 if (!safe_read_cint (param_count, ptr, end))
1367 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1369 if (!parse_custom_mods (ctx, &ptr, end))
1372 if (!parse_type (ctx, &ptr, end))
1373 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1375 for (i = 0; i < param_count; ++i) {
1376 if (!parse_type (ctx, &ptr, end))
1377 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1385 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1387 const char *ptr = *_ptr;
1388 guint8 signature = 0;
1390 if (!safe_read8 (signature, ptr, end))
1391 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1393 if (signature != 0x06)
1394 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1397 if (!parse_custom_mods (ctx, _ptr, end))
1400 return parse_type (ctx, _ptr, end);
1404 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1407 unsigned locals_count = 0, i;
1408 const char *ptr = *_ptr;
1410 if (!safe_read8 (sig, ptr, end))
1411 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1414 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1416 if (!safe_read_cint (locals_count, ptr, end))
1417 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1419 if (locals_count == 0)
1420 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1422 for (i = 0; i < locals_count; ++i) {
1423 if (!safe_read8 (sig, ptr, end))
1424 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1426 if (sig == MONO_TYPE_TYPEDBYREF)
1429 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1430 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1431 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1432 if (!safe_read8 (sig, ptr, end))
1433 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1436 if (!parse_type (ctx, &ptr, end))
1437 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1445 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1447 int size = 0, signature = 0;
1448 const char *ptr = NULL, *end;
1450 if (!decode_signature_header (ctx, offset, &size, &ptr))
1451 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1454 if (!safe_read8 (signature, ptr, end))
1455 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1458 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1461 return parse_field (ctx, &ptr, end);
1465 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1468 const char *ptr = NULL, *end;
1470 if (!decode_signature_header (ctx, offset, &size, &ptr))
1471 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1474 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1478 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1481 unsigned signature = 0;
1482 const char *ptr = NULL, *end;
1484 if (!decode_signature_header (ctx, offset, &size, &ptr))
1485 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1488 if (!safe_read8 (signature, ptr, end))
1489 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1492 if (signature == 0x06)
1493 return parse_field (ctx, &ptr, end);
1495 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1499 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1501 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1502 //TODO do proper verification
1503 return blob.size >= 1 && blob.size - 1 >= offset;
1507 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1509 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1510 //TODO do proper verification
1511 return blob.size >= 1 && blob.size - 1 >= offset;
1515 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1517 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1518 //TODO do proper verification
1519 return blob.size >= 1 && blob.size - 1 >= offset;
1523 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1526 unsigned signature = 0;
1527 const char *ptr = NULL, *end;
1529 if (!decode_signature_header (ctx, offset, &size, &ptr))
1530 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1533 if (!safe_read8 (signature, ptr, end))
1534 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1537 if (signature == 0x07)
1538 return parse_locals_signature (ctx, &ptr, end);
1539 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1543 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1546 const char *ptr = NULL, *end;
1548 if (!decode_signature_header (ctx, offset, &size, &ptr))
1549 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
1552 return parse_property_signature (ctx, &ptr, end);
1556 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1558 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1559 //TODO do proper verification
1560 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1564 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1566 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1567 //TODO do proper verification
1568 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1572 is_valid_blob_object (VerifyContext *ctx, guint32 offset)
1574 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1575 guint32 entry_size, bytes;
1577 if (blob.size < offset) {
1582 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1585 if (offset + entry_size + bytes < offset)
1588 return blob.size >= offset + entry_size + bytes;
1592 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1594 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1595 guint32 size, entry_size, bytes;
1597 if (blob.size < offset) {
1603 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1606 if (type == MONO_TYPE_STRING) {
1607 //String is encoded as: compressed_int:len len *chars
1610 if (offset > offset + entry_size * 2) //overflow
1612 offset += offset + entry_size * 2;
1613 return offset <= blob.size;
1617 case MONO_TYPE_BOOLEAN:
1622 case MONO_TYPE_CHAR:
1630 case MONO_TYPE_CLASS:
1640 g_assert_not_reached ();
1643 if (size != entry_size)
1647 if(offset > offset + size) //overflow
1650 if (offset + size > blob.size)
1653 if (type == MONO_TYPE_CLASS && read32 (ctx->data + offset))
1659 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1661 //TODO do proper method header validation
1662 return mono_cli_rva_image_map (ctx->image, rva) != INVALID_ADDRESS;
1666 verify_module_table (VerifyContext *ctx)
1668 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1669 guint32 data [MONO_MODULE_SIZE];
1671 if (table->rows != 1)
1672 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1674 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1676 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1677 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1679 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1680 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1682 if (data [MONO_MODULE_ENC] != 0)
1683 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1685 if (data [MONO_MODULE_ENCBASE] != 0)
1686 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1690 verify_typeref_table (VerifyContext *ctx)
1692 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1693 guint32 data [MONO_TYPEREF_SIZE];
1696 for (i = 0; i < table->rows; ++i) {
1697 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1698 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1699 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1701 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1702 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1704 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1705 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1707 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1708 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
1712 /*bits 9,11,14,15,19,21,24-31 */
1713 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
1715 verify_typedef_table (VerifyContext *ctx)
1717 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1718 guint32 data [MONO_TYPEDEF_SIZE];
1719 guint32 fieldlist = 1, methodlist = 1;
1722 if (table->rows == 0)
1723 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
1725 for (i = 0; i < table->rows; ++i) {
1726 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
1727 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
1728 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
1730 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
1731 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
1733 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
1734 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1736 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
1737 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1739 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
1740 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
1742 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1743 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
1746 if (data [MONO_TYPEDEF_EXTENDS] != 0)
1747 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
1749 if (typedef_is_system_object (ctx, data) && data [MONO_TYPEDEF_EXTENDS] != 0)
1750 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
1752 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
1753 if (data [MONO_TYPEDEF_EXTENDS])
1754 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
1755 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
1756 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
1758 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1759 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
1761 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1762 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
1766 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
1767 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
1769 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
1770 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
1772 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
1773 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));
1775 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
1776 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
1778 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
1779 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
1781 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
1782 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));
1785 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
1786 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
1791 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
1793 verify_field_table (VerifyContext *ctx)
1795 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
1796 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
1799 module_field_list = (guint32)-1;
1800 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1801 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1802 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
1805 for (i = 0; i < table->rows; ++i) {
1806 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
1807 flags = data [MONO_FIELD_FLAGS];
1809 if (flags & INVALID_FIELD_FLAG_BITS)
1810 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
1812 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
1813 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
1815 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
1816 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
1818 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
1819 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
1821 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
1822 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
1824 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
1825 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
1826 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
1828 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
1829 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1830 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1832 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
1833 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1834 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
1836 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
1837 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
1838 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1840 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
1841 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
1843 //TODO verify contant flag
1844 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
1845 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
1847 if (i + 1 < module_field_list) {
1848 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
1849 if (!(flags & FIELD_ATTRIBUTE_STATIC))
1850 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
1851 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
1852 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
1857 /*bits 6,8,9,10,11,13,14,15*/
1858 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
1860 verify_method_table (VerifyContext *ctx)
1862 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1863 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
1864 guint32 paramlist = 1;
1865 gboolean is_ctor, is_cctor;
1869 module_method_list = (guint32)-1;
1870 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1871 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1872 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
1875 for (i = 0; i < table->rows; ++i) {
1876 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
1877 rva = data [MONO_METHOD_RVA];
1878 implflags = data [MONO_METHOD_IMPLFLAGS];
1879 flags = data [MONO_METHOD_FLAGS];
1880 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
1881 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
1884 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
1885 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
1888 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
1890 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
1891 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
1893 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
1894 is_ctor = !strcmp (".ctor", name);
1895 is_cctor = !strcmp (".cctor", name);
1897 if ((is_ctor || is_cctor) &&
1898 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
1899 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
1901 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
1902 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
1904 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
1905 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1906 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
1907 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
1908 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
1911 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
1912 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
1914 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
1915 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
1917 //XXX no checks against cas stuff 10,11,12,13)
1919 //TODO check iface with .ctor (15,16)
1921 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
1922 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
1924 if (i + 1 < module_method_list) {
1925 if (!(flags & METHOD_ATTRIBUTE_STATIC))
1926 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
1927 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
1928 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
1929 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
1930 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
1933 //TODO check valuetype for synchronized
1935 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
1936 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
1938 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
1939 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
1941 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
1942 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1943 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
1945 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
1946 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
1948 //TODO check signature contents
1951 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
1952 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
1953 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
1954 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
1955 if (!is_valid_method_header (ctx, rva))
1956 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
1958 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1959 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
1962 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
1964 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
1965 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
1966 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
1968 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
1969 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
1971 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
1972 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
1974 if (data [MONO_METHOD_PARAMLIST] == 0)
1975 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
1977 if (data [MONO_METHOD_PARAMLIST] < paramlist)
1978 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));
1980 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
1981 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
1983 paramlist = data [MONO_METHOD_PARAMLIST];
1989 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
1991 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1992 guint32 row = *current_method;
1993 guint32 paramlist, tmp;
1996 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
1997 while (row < table->rows) {
1998 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
1999 if (tmp > paramlist) {
2000 *current_method = row;
2001 return tmp - paramlist;
2006 /*no more methods, all params apply to the last one*/
2007 *current_method = table->rows;
2012 #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))
2014 verify_param_table (VerifyContext *ctx)
2016 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2017 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2018 gboolean first_param = TRUE;
2021 remaining_params = get_next_param_count (ctx, ¤t_method);
2023 for (i = 0; i < table->rows; ++i) {
2024 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2025 flags = data [MONO_PARAM_FLAGS];
2027 if (flags & INVALID_PARAM_FLAGS_BITS)
2028 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2030 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2031 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2032 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2034 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2035 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2038 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)
2039 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2041 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2042 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2044 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2045 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2047 first_param = FALSE;
2048 sequence = data [MONO_PARAM_SEQUENCE];
2049 if (--remaining_params == 0) {
2050 remaining_params = get_next_param_count (ctx, ¤t_method);
2057 verify_interfaceimpl_table (VerifyContext *ctx)
2059 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2060 guint32 data [MONO_INTERFACEIMPL_SIZE];
2063 for (i = 0; i < table->rows; ++i) {
2064 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2065 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2066 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2068 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2069 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2071 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2072 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2077 verify_memberref_table (VerifyContext *ctx)
2079 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2080 guint32 data [MONO_MEMBERREF_SIZE];
2083 for (i = 0; i < table->rows; ++i) {
2084 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2086 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2087 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2089 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2090 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2092 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2093 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2095 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2096 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2101 verify_constant_table (VerifyContext *ctx)
2103 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2104 guint32 data [MONO_CONSTANT_SIZE], type;
2107 for (i = 0; i < table->rows; ++i) {
2108 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2109 type = data [MONO_CONSTANT_TYPE];
2111 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2112 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2114 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2115 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2117 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2118 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2120 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2121 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2126 verify_cattr_table (VerifyContext *ctx)
2128 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2129 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2132 for (i = 0; i < table->rows; ++i) {
2133 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2135 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2136 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2138 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2139 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2141 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2142 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2148 verify_field_marshal_table (VerifyContext *ctx)
2150 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2151 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2154 for (i = 0; i < table->rows; ++i) {
2155 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2157 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2158 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2160 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2161 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2163 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2164 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2166 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2167 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2173 verify_decl_security_table (VerifyContext *ctx)
2175 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2176 guint32 data [MONO_DECL_SECURITY_SIZE];
2179 for (i = 0; i < table->rows; ++i) {
2180 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2182 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2183 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2185 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2186 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2188 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2189 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2191 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2192 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2198 verify_class_layout_table (VerifyContext *ctx)
2200 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2201 guint32 data [MONO_CLASS_LAYOUT_SIZE];
2204 for (i = 0; i < table->rows; ++i) {
2205 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2207 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2208 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2210 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2222 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2228 verify_field_layout_table (VerifyContext *ctx)
2230 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2231 guint32 data [MONO_FIELD_LAYOUT_SIZE];
2234 for (i = 0; i < table->rows; ++i) {
2235 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2237 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2238 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2243 verify_standalonesig_table (VerifyContext *ctx)
2245 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2246 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2249 for (i = 0; i < table->rows; ++i) {
2250 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2252 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2253 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2258 verify_eventmap_table (VerifyContext *ctx)
2260 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2261 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2264 for (i = 0; i < table->rows; ++i) {
2265 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2267 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2268 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2270 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2271 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2273 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2277 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2279 verify_event_table (VerifyContext *ctx)
2281 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2282 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2283 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2284 gboolean found_add, found_remove;
2287 for (i = 0; i < table->rows; ++i) {
2288 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2290 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2291 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2293 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2294 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2296 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2297 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2299 //check for Add and Remove
2300 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2301 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2303 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2305 //first we move to the first row for this event
2307 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2311 //now move forward looking for AddOn and RemoveOn rows
2312 found_add = found_remove = FALSE;
2313 while (idx < sema_table->rows) {
2314 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2315 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2317 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2319 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2320 found_remove = TRUE;
2321 if (found_add && found_remove)
2327 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2329 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2334 verify_propertymap_table (VerifyContext *ctx)
2336 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2337 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2340 for (i = 0; i < table->rows; ++i) {
2341 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2343 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2344 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2346 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2347 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2349 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2353 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2355 verify_property_table (VerifyContext *ctx)
2357 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2358 guint32 data [MONO_PROPERTY_SIZE];
2361 for (i = 0; i < table->rows; ++i) {
2362 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2364 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2365 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2367 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2368 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2370 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2371 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2373 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2374 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2375 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2381 verify_methodimpl_table (VerifyContext *ctx)
2383 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2384 guint32 data [MONO_METHODIMPL_SIZE];
2387 for (i = 0; i < table->rows; ++i) {
2388 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2390 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2391 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2393 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2394 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2396 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2397 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2399 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2400 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2402 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2403 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2408 verify_moduleref_table (VerifyContext *ctx)
2410 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2411 guint32 data [MONO_MODULEREF_SIZE];
2414 for (i = 0; i < table->rows; ++i) {
2415 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2417 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2418 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2423 verify_typespec_table (VerifyContext *ctx)
2425 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2426 guint32 data [MONO_TYPESPEC_SIZE];
2429 for (i = 0; i < table->rows; ++i) {
2430 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2432 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2433 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2437 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10))
2439 verify_implmap_table (VerifyContext *ctx)
2441 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2442 guint32 data [MONO_IMPLMAP_SIZE], cconv;
2445 for (i = 0; i < table->rows; ++i) {
2446 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2448 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2449 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2451 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2452 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2453 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2455 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2456 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2458 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2459 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2461 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2462 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2464 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2465 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2467 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULE].rows + 1)
2468 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2473 verify_fieldrva_table (VerifyContext *ctx)
2475 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2476 guint32 data [MONO_FIELD_RVA_SIZE];
2479 for (i = 0; i < table->rows; ++i) {
2480 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2482 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2483 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2485 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2486 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2490 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
2492 verify_assembly_table (VerifyContext *ctx)
2494 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2495 guint32 data [MONO_ASSEMBLY_SIZE], hash;
2498 if (table->rows > 1)
2499 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2501 for (i = 0; i < table->rows; ++i) {
2502 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2504 hash = data [MONO_ASSEMBLY_HASH_ALG];
2505 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2506 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2508 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2509 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2511 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY]))
2512 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2514 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2515 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2517 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2518 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2522 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2524 verify_assemblyref_table (VerifyContext *ctx)
2526 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2527 guint32 data [MONO_ASSEMBLYREF_SIZE];
2530 for (i = 0; i < table->rows; ++i) {
2531 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2533 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2534 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2536 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY]))
2537 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2539 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2540 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
2542 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
2543 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
2545 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE]))
2546 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
2550 #define INVALID_FILE_FLAGS_BITS ~(1)
2552 verify_file_table (VerifyContext *ctx)
2554 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
2555 guint32 data [MONO_FILE_SIZE];
2558 for (i = 0; i < table->rows; ++i) {
2559 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
2561 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
2562 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
2564 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
2565 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
2567 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE]))
2568 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
2572 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
2574 verify_exportedtype_table (VerifyContext *ctx)
2576 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
2577 guint32 data [MONO_EXP_TYPE_SIZE];
2580 for (i = 0; i < table->rows; ++i) {
2581 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
2583 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
2584 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
2586 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
2587 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
2589 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
2590 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
2592 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2593 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
2595 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2596 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
2598 /*nested type can't have a namespace*/
2599 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
2600 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
2604 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
2606 verify_manifest_resource_table (VerifyContext *ctx)
2608 MonoCLIImageInfo *iinfo = ctx->image->image_info;
2609 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2610 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
2611 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
2614 resources_size = ch->ch_resources.size;
2616 for (i = 0; i < table->rows; ++i) {
2617 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
2619 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
2620 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
2622 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
2623 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
2625 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
2626 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
2628 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
2629 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
2631 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2632 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2634 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
2635 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])));
2637 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
2638 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
2640 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
2641 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
2646 verify_nested_class_table (VerifyContext *ctx)
2648 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
2649 guint32 data [MONO_NESTED_CLASS_SIZE];
2652 for (i = 0; i < table->rows; ++i) {
2653 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
2655 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2656 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
2657 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2658 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2659 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
2660 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2664 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
2666 verify_generic_param_table (VerifyContext *ctx)
2668 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
2669 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
2670 int i, param_number = 0;
2672 for (i = 0; i < table->rows; ++i) {
2673 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
2675 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
2676 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
2678 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
2679 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
2681 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
2682 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
2684 token = data [MONO_GENERICPARAM_OWNER];
2686 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
2687 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
2689 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
2690 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
2692 if (token != last_token) {
2697 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
2698 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));
2705 verify_method_spec_table (VerifyContext *ctx)
2707 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
2708 guint32 data [MONO_METHODSPEC_SIZE];
2711 for (i = 0; i < table->rows; ++i) {
2712 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
2714 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2715 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
2717 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2718 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
2720 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
2721 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
2726 verify_generic_param_constraint_table (VerifyContext *ctx)
2728 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
2729 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
2732 for (i = 0; i < table->rows; ++i) {
2733 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
2735 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
2736 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
2738 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2739 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
2741 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2742 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
2747 verify_tables_data (VerifyContext *ctx)
2749 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
2750 guint32 size = 0, tables_offset;
2753 for (i = 0; i < 0x2D; ++i) {
2754 MonoTableInfo *table = &ctx->image->tables [i];
2756 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
2757 if (tmp_size < size) {
2765 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
2767 tables_offset = ctx->image->tables_base - ctx->data;
2768 if (!bounds_check_offset (&tables_area, tables_offset, size))
2769 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)));
2771 verify_module_table (ctx);
2773 verify_typeref_table (ctx);
2775 verify_typedef_table (ctx);
2777 verify_field_table (ctx);
2779 verify_method_table (ctx);
2781 verify_param_table (ctx);
2783 verify_interfaceimpl_table (ctx);
2785 verify_memberref_table (ctx);
2787 verify_constant_table (ctx);
2789 verify_cattr_table (ctx);
2791 verify_field_marshal_table (ctx);
2793 verify_decl_security_table (ctx);
2795 verify_class_layout_table (ctx);
2797 verify_field_layout_table (ctx);
2799 verify_standalonesig_table (ctx);
2801 verify_eventmap_table (ctx);
2803 verify_event_table (ctx);
2805 verify_propertymap_table (ctx);
2807 verify_property_table (ctx);
2809 verify_methodimpl_table (ctx);
2811 verify_moduleref_table (ctx);
2813 verify_typespec_table (ctx);
2815 verify_implmap_table (ctx);
2817 verify_fieldrva_table (ctx);
2819 verify_assembly_table (ctx);
2821 verify_assemblyref_table (ctx);
2823 verify_file_table (ctx);
2825 verify_exportedtype_table (ctx);
2827 verify_manifest_resource_table (ctx);
2829 verify_nested_class_table (ctx);
2831 verify_generic_param_table (ctx);
2833 verify_method_spec_table (ctx);
2835 verify_generic_param_constraint_table (ctx);
2839 mono_verifier_is_corlib (MonoImage *image)
2841 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
2842 TRUE : mono_security_core_clr_is_platform_image (image);
2844 return trusted_location && !strcmp ("mscorlib.dll", image->name);
2848 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
2850 memset (ctx, 0, sizeof (VerifyContext));
2852 ctx->report_error = error_list != NULL;
2854 ctx->size = image->raw_data_len;
2855 ctx->data = image->raw_data;
2856 ctx->is_corlib = mono_verifier_is_corlib (image);
2860 cleanup_context (VerifyContext *ctx, GSList **error_list)
2862 g_free (ctx->sections);
2864 *error_list = ctx->errors;
2866 mono_free_verify_list (ctx->errors);
2871 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2875 if (!mono_verifier_is_enabled_for_image (image))
2878 init_verify_context (&ctx, image, error_list);
2879 ctx.stage = STAGE_PE;
2881 verify_msdos_header (&ctx);
2883 verify_pe_header (&ctx);
2885 verify_pe_optional_header (&ctx);
2887 load_section_table (&ctx);
2889 load_data_directories (&ctx);
2891 verify_import_table (&ctx);
2893 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
2894 verify_resources_table (&ctx);
2897 return cleanup_context (&ctx, error_list);
2901 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2905 if (!mono_verifier_is_enabled_for_image (image))
2908 init_verify_context (&ctx, image, error_list);
2909 ctx.stage = STAGE_CLI;
2911 verify_cli_header (&ctx);
2913 verify_metadata_header (&ctx);
2915 verify_tables_schema (&ctx);
2918 return cleanup_context (&ctx, error_list);
2922 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2926 if (!mono_verifier_is_enabled_for_image (image))
2929 init_verify_context (&ctx, image, error_list);
2930 ctx.stage = STAGE_TABLES;
2932 verify_tables_data (&ctx);
2934 return cleanup_context (&ctx, error_list);
2938 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2944 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2950 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2954 #endif /* DISABLE_VERIFIER */