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_type (VerifyContext *ctx, const char **_ptr, const char *end)
1155 const char *ptr = *_ptr;
1158 if (!safe_read8 (type, ptr, end))
1159 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1161 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1162 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1163 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1164 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1165 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1172 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1177 if (!parse_custom_mods (ctx, _ptr, end))
1181 if (!safe_read8 (type, ptr, end))
1182 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1184 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1189 //it's a byref, update the cursor ptr
1190 if (type == MONO_TYPE_BYREF)
1193 return parse_type (ctx, _ptr, end);
1197 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1202 if (!parse_custom_mods (ctx, _ptr, end))
1206 if (!safe_read8 (type, ptr, end))
1207 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1209 if (type == MONO_TYPE_TYPEDBYREF) {
1214 //it's a byref, update the cursor ptr
1215 if (type == MONO_TYPE_BYREF)
1218 return parse_type (ctx, _ptr, end);
1222 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1225 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1226 const char *ptr = *_ptr;
1227 gboolean saw_sentinel = FALSE;
1229 if (!safe_read8 (cconv, ptr, end))
1230 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1233 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1235 if (allow_unmanaged) {
1236 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1237 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1238 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1239 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1241 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1242 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1244 if ((cconv & 0x10) && gparam_count == 0)
1245 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1247 if (allow_unmanaged && (cconv & 0x10))
1248 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1250 if (!safe_read_cint (param_count, ptr, end))
1251 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1253 if (!parse_return_type (ctx, &ptr, end))
1254 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1256 for (i = 0; i < param_count; ++i) {
1257 if (allow_sentinel) {
1258 if (!safe_read8 (type, ptr, end))
1259 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1261 if (type == MONO_TYPE_SENTINEL) {
1262 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1263 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1266 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1268 saw_sentinel = TRUE;
1274 if (!parse_param (ctx, &ptr, end))
1275 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1283 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1285 if (!parse_custom_mods (ctx, _ptr, end))
1287 return parse_type (ctx, _ptr, end);
1291 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1293 int size = 0, signature = 0;
1294 const char *ptr = NULL, *end;
1296 if (!decode_signature_header (ctx, offset, &size, &ptr))
1297 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1300 if (!safe_read8 (signature, ptr, end))
1301 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1304 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1307 return parse_field (ctx, &ptr, end);
1311 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1314 const char *ptr = NULL, *end;
1316 if (!decode_signature_header (ctx, offset, &size, &ptr))
1317 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1320 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1324 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1327 unsigned signature = 0;
1328 const char *ptr = NULL, *end;
1330 if (!decode_signature_header (ctx, offset, &size, &ptr))
1331 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1334 if (!safe_read8 (signature, ptr, end))
1335 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1338 if (signature == 0x06)
1339 return parse_field (ctx, &ptr, end);
1341 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1345 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1347 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1348 //TODO do proper verification
1349 return blob.size >= 1 && blob.size - 1 >= offset;
1353 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1355 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1356 //TODO do proper verification
1357 return blob.size >= 1 && blob.size - 1 >= offset;
1361 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1363 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1364 //TODO do proper verification
1365 return blob.size >= 1 && blob.size - 1 >= offset;
1369 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1372 unsigned signature = 0;
1373 const char *ptr = NULL, *end;
1375 if (!decode_signature_header (ctx, offset, &size, &ptr))
1376 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1379 if (!safe_read8 (signature, ptr, end))
1380 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1382 if (signature == 0x07) //FIXME implement localvarsig checking
1386 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1390 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1392 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1393 //TODO do proper verification
1394 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1398 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1400 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1401 //TODO do proper verification
1402 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1406 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1408 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1409 //TODO do proper verification
1410 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1414 is_valid_blob_object (VerifyContext *ctx, guint32 offset)
1416 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1417 guint32 entry_size, bytes;
1419 if (blob.size < offset) {
1424 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1427 if (offset + entry_size + bytes < offset)
1430 return blob.size >= offset + entry_size + bytes;
1434 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1436 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1437 guint32 size, entry_size, bytes;
1439 if (blob.size < offset) {
1445 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1448 if (type == MONO_TYPE_STRING) {
1449 //String is encoded as: compressed_int:len len *chars
1452 if (offset > offset + entry_size * 2) //overflow
1454 offset += offset + entry_size * 2;
1455 return offset <= blob.size;
1459 case MONO_TYPE_BOOLEAN:
1464 case MONO_TYPE_CHAR:
1472 case MONO_TYPE_CLASS:
1482 g_assert_not_reached ();
1485 if (size != entry_size)
1489 if(offset > offset + size) //overflow
1492 if (offset + size > blob.size)
1495 if (type == MONO_TYPE_CLASS && read32 (ctx->data + offset))
1501 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1503 //TODO do proper method header validation
1504 return mono_cli_rva_image_map (ctx->image, rva) != INVALID_ADDRESS;
1508 verify_module_table (VerifyContext *ctx)
1510 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1511 guint32 data [MONO_MODULE_SIZE];
1513 if (table->rows != 1)
1514 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1516 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1518 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1519 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1521 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1522 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1524 if (data [MONO_MODULE_ENC] != 0)
1525 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1527 if (data [MONO_MODULE_ENCBASE] != 0)
1528 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1532 verify_typeref_table (VerifyContext *ctx)
1534 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1535 guint32 data [MONO_TYPEREF_SIZE];
1538 for (i = 0; i < table->rows; ++i) {
1539 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1540 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1541 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1543 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1544 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1546 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1547 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1549 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1550 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
1554 /*bits 9,11,14,15,19,21,24-31 */
1555 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
1557 verify_typedef_table (VerifyContext *ctx)
1559 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1560 guint32 data [MONO_TYPEDEF_SIZE];
1561 guint32 fieldlist = 1, methodlist = 1;
1564 if (table->rows == 0)
1565 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
1567 for (i = 0; i < table->rows; ++i) {
1568 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
1569 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
1570 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
1572 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
1573 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
1575 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
1576 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1578 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
1579 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1581 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
1582 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
1584 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1585 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
1588 if (data [MONO_TYPEDEF_EXTENDS] != 0)
1589 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
1591 if (typedef_is_system_object (ctx, data) && data [MONO_TYPEDEF_EXTENDS] != 0)
1592 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
1594 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
1595 if (data [MONO_TYPEDEF_EXTENDS])
1596 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
1597 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
1598 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
1600 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1601 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
1603 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1604 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
1608 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
1609 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
1611 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
1612 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
1614 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
1615 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));
1617 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
1618 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
1620 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
1621 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
1623 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
1624 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));
1627 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
1628 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
1633 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
1635 verify_field_table (VerifyContext *ctx)
1637 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
1638 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
1641 module_field_list = (guint32)-1;
1642 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1643 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1644 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
1647 for (i = 0; i < table->rows; ++i) {
1648 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
1649 flags = data [MONO_FIELD_FLAGS];
1651 if (flags & INVALID_FIELD_FLAG_BITS)
1652 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
1654 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
1655 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
1657 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
1658 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
1660 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
1661 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
1663 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
1664 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
1666 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
1667 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
1668 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
1670 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
1671 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1672 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1674 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
1675 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1676 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
1678 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
1679 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
1680 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1682 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
1683 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
1685 //TODO verify contant flag
1686 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
1687 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
1689 if (i + 1 < module_field_list) {
1690 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
1691 if (!(flags & FIELD_ATTRIBUTE_STATIC))
1692 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
1693 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
1694 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
1699 /*bits 6,8,9,10,11,13,14,15*/
1700 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
1702 verify_method_table (VerifyContext *ctx)
1704 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1705 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
1706 guint32 paramlist = 1;
1707 gboolean is_ctor, is_cctor;
1711 module_method_list = (guint32)-1;
1712 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1713 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1714 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
1717 for (i = 0; i < table->rows; ++i) {
1718 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
1719 rva = data [MONO_METHOD_RVA];
1720 implflags = data [MONO_METHOD_IMPLFLAGS];
1721 flags = data [MONO_METHOD_FLAGS];
1722 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
1723 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
1726 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
1727 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
1730 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
1732 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
1733 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
1735 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
1736 is_ctor = !strcmp (".ctor", name);
1737 is_cctor = !strcmp (".cctor", name);
1739 if ((is_ctor || is_cctor) &&
1740 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
1741 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
1743 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
1744 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
1746 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
1747 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1748 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
1749 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
1750 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
1753 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
1754 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
1756 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
1757 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
1759 //XXX no checks against cas stuff 10,11,12,13)
1761 //TODO check iface with .ctor (15,16)
1763 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
1764 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
1766 if (i + 1 < module_method_list) {
1767 if (!(flags & METHOD_ATTRIBUTE_STATIC))
1768 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
1769 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
1770 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
1771 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
1772 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
1775 //TODO check valuetype for synchronized
1777 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
1778 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
1780 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
1781 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
1783 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
1784 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1785 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
1787 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
1788 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
1790 //TODO check signature contents
1793 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
1794 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
1795 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
1796 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
1797 if (!is_valid_method_header (ctx, rva))
1798 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
1800 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1801 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
1804 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
1806 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
1807 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
1808 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
1810 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
1811 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
1813 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
1814 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
1816 if (data [MONO_METHOD_PARAMLIST] == 0)
1817 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
1819 if (data [MONO_METHOD_PARAMLIST] < paramlist)
1820 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));
1822 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
1823 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
1825 paramlist = data [MONO_METHOD_PARAMLIST];
1831 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
1833 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1834 guint32 row = *current_method;
1835 guint32 paramlist, tmp;
1838 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
1839 while (row < table->rows) {
1840 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
1841 if (tmp > paramlist) {
1842 *current_method = row;
1843 return tmp - paramlist;
1848 /*no more methods, all params apply to the last one*/
1849 *current_method = table->rows;
1854 #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))
1856 verify_param_table (VerifyContext *ctx)
1858 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
1859 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
1860 gboolean first_param = TRUE;
1863 remaining_params = get_next_param_count (ctx, ¤t_method);
1865 for (i = 0; i < table->rows; ++i) {
1866 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
1867 flags = data [MONO_PARAM_FLAGS];
1869 if (flags & INVALID_PARAM_FLAGS_BITS)
1870 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
1872 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
1873 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
1874 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
1876 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
1877 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
1880 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)
1881 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
1883 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
1884 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
1886 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
1887 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
1889 first_param = FALSE;
1890 sequence = data [MONO_PARAM_SEQUENCE];
1891 if (--remaining_params == 0) {
1892 remaining_params = get_next_param_count (ctx, ¤t_method);
1899 verify_interfaceimpl_table (VerifyContext *ctx)
1901 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
1902 guint32 data [MONO_INTERFACEIMPL_SIZE];
1905 for (i = 0; i < table->rows; ++i) {
1906 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
1907 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
1908 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
1910 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
1911 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
1913 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
1914 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
1919 verify_memberref_table (VerifyContext *ctx)
1921 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
1922 guint32 data [MONO_MEMBERREF_SIZE];
1925 for (i = 0; i < table->rows; ++i) {
1926 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
1928 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
1929 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
1931 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
1932 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
1934 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
1935 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
1937 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
1938 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
1943 verify_constant_table (VerifyContext *ctx)
1945 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
1946 guint32 data [MONO_CONSTANT_SIZE], type;
1949 for (i = 0; i < table->rows; ++i) {
1950 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
1951 type = data [MONO_CONSTANT_TYPE];
1953 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
1954 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
1956 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
1957 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
1959 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
1960 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
1962 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
1963 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
1968 verify_cattr_table (VerifyContext *ctx)
1970 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1971 guint32 data [MONO_CUSTOM_ATTR_SIZE];
1974 for (i = 0; i < table->rows; ++i) {
1975 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
1977 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
1978 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
1980 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
1981 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
1983 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
1984 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
1990 verify_field_marshal_table (VerifyContext *ctx)
1992 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
1993 guint32 data [MONO_FIELD_MARSHAL_SIZE];
1996 for (i = 0; i < table->rows; ++i) {
1997 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
1999 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2000 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2002 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2003 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2005 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2006 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2008 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2009 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2015 verify_decl_security_table (VerifyContext *ctx)
2017 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2018 guint32 data [MONO_DECL_SECURITY_SIZE];
2021 for (i = 0; i < table->rows; ++i) {
2022 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2024 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2025 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2027 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2028 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2030 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2031 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2033 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2034 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2040 verify_class_layout_table (VerifyContext *ctx)
2042 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2043 guint32 data [MONO_CLASS_LAYOUT_SIZE];
2046 for (i = 0; i < table->rows; ++i) {
2047 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2049 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2050 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2052 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2064 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2070 verify_field_layout_table (VerifyContext *ctx)
2072 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2073 guint32 data [MONO_FIELD_LAYOUT_SIZE];
2076 for (i = 0; i < table->rows; ++i) {
2077 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2079 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2080 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2085 verify_standalonesig_table (VerifyContext *ctx)
2087 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2088 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2091 for (i = 0; i < table->rows; ++i) {
2092 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2094 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2095 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2100 verify_eventmap_table (VerifyContext *ctx)
2102 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2103 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2106 for (i = 0; i < table->rows; ++i) {
2107 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2109 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2110 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2112 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2113 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2115 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2119 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2121 verify_event_table (VerifyContext *ctx)
2123 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2124 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2125 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2126 gboolean found_add, found_remove;
2129 for (i = 0; i < table->rows; ++i) {
2130 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2132 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2133 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2135 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2136 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2138 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2139 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2141 //check for Add and Remove
2142 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2143 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2145 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2147 //first we move to the first row for this event
2149 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2153 //now move forward looking for AddOn and RemoveOn rows
2154 found_add = found_remove = FALSE;
2155 while (idx < sema_table->rows) {
2156 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2157 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2159 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2161 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2162 found_remove = TRUE;
2163 if (found_add && found_remove)
2169 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2171 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2176 verify_propertymap_table (VerifyContext *ctx)
2178 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2179 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2182 for (i = 0; i < table->rows; ++i) {
2183 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2185 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2186 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2188 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2189 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2191 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2195 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2197 verify_property_table (VerifyContext *ctx)
2199 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2200 guint32 data [MONO_PROPERTY_SIZE];
2203 for (i = 0; i < table->rows; ++i) {
2204 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2206 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2207 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2209 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2210 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2212 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2213 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2215 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2216 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2217 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2223 verify_methodimpl_table (VerifyContext *ctx)
2225 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2226 guint32 data [MONO_METHODIMPL_SIZE];
2229 for (i = 0; i < table->rows; ++i) {
2230 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2232 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2233 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2235 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2236 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2238 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2239 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2241 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2242 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2244 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2245 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2250 verify_moduleref_table (VerifyContext *ctx)
2252 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2253 guint32 data [MONO_MODULEREF_SIZE];
2256 for (i = 0; i < table->rows; ++i) {
2257 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2259 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2260 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2265 verify_typespec_table (VerifyContext *ctx)
2267 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2268 guint32 data [MONO_TYPESPEC_SIZE];
2271 for (i = 0; i < table->rows; ++i) {
2272 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2274 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2275 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2279 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10))
2281 verify_implmap_table (VerifyContext *ctx)
2283 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2284 guint32 data [MONO_IMPLMAP_SIZE], cconv;
2287 for (i = 0; i < table->rows; ++i) {
2288 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2290 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2291 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2293 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2294 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2295 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2297 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2298 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2300 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2301 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2303 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2304 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2306 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2307 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2309 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULE].rows + 1)
2310 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2315 verify_fieldrva_table (VerifyContext *ctx)
2317 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2318 guint32 data [MONO_FIELD_RVA_SIZE];
2321 for (i = 0; i < table->rows; ++i) {
2322 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2324 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2325 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2327 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2328 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2332 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
2334 verify_assembly_table (VerifyContext *ctx)
2336 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2337 guint32 data [MONO_ASSEMBLY_SIZE], hash;
2340 if (table->rows > 1)
2341 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2343 for (i = 0; i < table->rows; ++i) {
2344 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2346 hash = data [MONO_ASSEMBLY_HASH_ALG];
2347 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2348 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2350 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2351 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2353 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY]))
2354 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2356 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2357 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2359 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2360 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2364 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2366 verify_assemblyref_table (VerifyContext *ctx)
2368 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2369 guint32 data [MONO_ASSEMBLYREF_SIZE];
2372 for (i = 0; i < table->rows; ++i) {
2373 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2375 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2376 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2378 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY]))
2379 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2381 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2382 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
2384 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
2385 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
2387 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE]))
2388 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
2392 #define INVALID_FILE_FLAGS_BITS ~(1)
2394 verify_file_table (VerifyContext *ctx)
2396 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
2397 guint32 data [MONO_FILE_SIZE];
2400 for (i = 0; i < table->rows; ++i) {
2401 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
2403 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
2404 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
2406 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
2407 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
2409 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE]))
2410 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
2414 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
2416 verify_exportedtype_table (VerifyContext *ctx)
2418 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
2419 guint32 data [MONO_EXP_TYPE_SIZE];
2422 for (i = 0; i < table->rows; ++i) {
2423 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
2425 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
2426 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
2428 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
2429 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
2431 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
2432 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
2434 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2435 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
2437 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2438 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
2440 /*nested type can't have a namespace*/
2441 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
2442 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
2446 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
2448 verify_manifest_resource_table (VerifyContext *ctx)
2450 MonoCLIImageInfo *iinfo = ctx->image->image_info;
2451 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2452 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
2453 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
2456 resources_size = ch->ch_resources.size;
2458 for (i = 0; i < table->rows; ++i) {
2459 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
2461 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
2462 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
2464 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
2465 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
2467 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
2468 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
2470 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
2471 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
2473 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2474 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2476 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
2477 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])));
2479 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
2480 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
2482 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
2483 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
2488 verify_nested_class_table (VerifyContext *ctx)
2490 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
2491 guint32 data [MONO_NESTED_CLASS_SIZE];
2494 for (i = 0; i < table->rows; ++i) {
2495 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
2497 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2498 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
2499 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2500 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2501 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
2502 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2506 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
2508 verify_generic_param_table (VerifyContext *ctx)
2510 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
2511 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
2512 int i, param_number = 0;
2514 for (i = 0; i < table->rows; ++i) {
2515 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
2517 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
2518 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
2520 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
2521 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
2523 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
2524 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
2526 token = data [MONO_GENERICPARAM_OWNER];
2528 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
2529 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
2531 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
2532 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
2534 if (token != last_token) {
2539 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
2540 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));
2547 verify_method_spec_table (VerifyContext *ctx)
2549 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
2550 guint32 data [MONO_METHODSPEC_SIZE];
2553 for (i = 0; i < table->rows; ++i) {
2554 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
2556 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2557 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
2559 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2560 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
2562 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
2563 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
2568 verify_generic_param_constraint_table (VerifyContext *ctx)
2570 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
2571 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
2574 for (i = 0; i < table->rows; ++i) {
2575 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
2577 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
2578 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
2580 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2581 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
2583 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2584 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
2589 verify_tables_data (VerifyContext *ctx)
2591 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
2592 guint32 size = 0, tables_offset;
2595 for (i = 0; i < 0x2D; ++i) {
2596 MonoTableInfo *table = &ctx->image->tables [i];
2598 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
2599 if (tmp_size < size) {
2607 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
2609 tables_offset = ctx->image->tables_base - ctx->data;
2610 if (!bounds_check_offset (&tables_area, tables_offset, size))
2611 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)));
2613 verify_module_table (ctx);
2615 verify_typeref_table (ctx);
2617 verify_typedef_table (ctx);
2619 verify_field_table (ctx);
2621 verify_method_table (ctx);
2623 verify_param_table (ctx);
2625 verify_interfaceimpl_table (ctx);
2627 verify_memberref_table (ctx);
2629 verify_constant_table (ctx);
2631 verify_cattr_table (ctx);
2633 verify_field_marshal_table (ctx);
2635 verify_decl_security_table (ctx);
2637 verify_class_layout_table (ctx);
2639 verify_field_layout_table (ctx);
2641 verify_standalonesig_table (ctx);
2643 verify_eventmap_table (ctx);
2645 verify_event_table (ctx);
2647 verify_propertymap_table (ctx);
2649 verify_property_table (ctx);
2651 verify_methodimpl_table (ctx);
2653 verify_moduleref_table (ctx);
2655 verify_typespec_table (ctx);
2657 verify_implmap_table (ctx);
2659 verify_fieldrva_table (ctx);
2661 verify_assembly_table (ctx);
2663 verify_assemblyref_table (ctx);
2665 verify_file_table (ctx);
2667 verify_exportedtype_table (ctx);
2669 verify_manifest_resource_table (ctx);
2671 verify_nested_class_table (ctx);
2673 verify_generic_param_table (ctx);
2675 verify_method_spec_table (ctx);
2677 verify_generic_param_constraint_table (ctx);
2681 mono_verifier_is_corlib (MonoImage *image)
2683 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
2684 TRUE : mono_security_core_clr_is_platform_image (image);
2686 return trusted_location && !strcmp ("mscorlib.dll", image->name);
2690 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
2692 memset (ctx, 0, sizeof (VerifyContext));
2694 ctx->report_error = error_list != NULL;
2696 ctx->size = image->raw_data_len;
2697 ctx->data = image->raw_data;
2698 ctx->is_corlib = mono_verifier_is_corlib (image);
2702 cleanup_context (VerifyContext *ctx, GSList **error_list)
2704 g_free (ctx->sections);
2706 *error_list = ctx->errors;
2708 mono_free_verify_list (ctx->errors);
2713 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2717 if (!mono_verifier_is_enabled_for_image (image))
2720 init_verify_context (&ctx, image, error_list);
2721 ctx.stage = STAGE_PE;
2723 verify_msdos_header (&ctx);
2725 verify_pe_header (&ctx);
2727 verify_pe_optional_header (&ctx);
2729 load_section_table (&ctx);
2731 load_data_directories (&ctx);
2733 verify_import_table (&ctx);
2735 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
2736 verify_resources_table (&ctx);
2739 return cleanup_context (&ctx, error_list);
2743 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2747 if (!mono_verifier_is_enabled_for_image (image))
2750 init_verify_context (&ctx, image, error_list);
2751 ctx.stage = STAGE_CLI;
2753 verify_cli_header (&ctx);
2755 verify_metadata_header (&ctx);
2757 verify_tables_schema (&ctx);
2760 return cleanup_context (&ctx, error_list);
2764 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2768 if (!mono_verifier_is_enabled_for_image (image))
2771 init_verify_context (&ctx, image, error_list);
2772 ctx.stage = STAGE_TABLES;
2774 verify_tables_data (&ctx);
2776 return cleanup_context (&ctx, error_list);
2780 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2786 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2792 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2796 #endif /* DISABLE_VERIFIER */