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_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1286 unsigned param_count = 0, i;
1287 const char *ptr = *_ptr;
1289 if (!safe_read8 (sig, ptr, end))
1290 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1292 if (sig != 0x08 && sig != 0x28)
1293 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1295 if (!safe_read_cint (param_count, ptr, end))
1296 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1298 if (!parse_custom_mods (ctx, &ptr, end))
1301 if (!parse_type (ctx, &ptr, end))
1302 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1304 for (i = 0; i < param_count; ++i) {
1305 if (!parse_type (ctx, &ptr, end))
1306 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1314 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1316 if (!parse_custom_mods (ctx, _ptr, end))
1318 return parse_type (ctx, _ptr, end);
1322 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1324 int size = 0, signature = 0;
1325 const char *ptr = NULL, *end;
1327 if (!decode_signature_header (ctx, offset, &size, &ptr))
1328 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1331 if (!safe_read8 (signature, ptr, end))
1332 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1335 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1338 return parse_field (ctx, &ptr, end);
1342 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1345 const char *ptr = NULL, *end;
1347 if (!decode_signature_header (ctx, offset, &size, &ptr))
1348 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1351 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1355 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1358 unsigned signature = 0;
1359 const char *ptr = NULL, *end;
1361 if (!decode_signature_header (ctx, offset, &size, &ptr))
1362 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1365 if (!safe_read8 (signature, ptr, end))
1366 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1369 if (signature == 0x06)
1370 return parse_field (ctx, &ptr, end);
1372 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1376 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1378 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1379 //TODO do proper verification
1380 return blob.size >= 1 && blob.size - 1 >= offset;
1384 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1386 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1387 //TODO do proper verification
1388 return blob.size >= 1 && blob.size - 1 >= offset;
1392 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1394 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1395 //TODO do proper verification
1396 return blob.size >= 1 && blob.size - 1 >= offset;
1400 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1403 unsigned signature = 0;
1404 const char *ptr = NULL, *end;
1406 if (!decode_signature_header (ctx, offset, &size, &ptr))
1407 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1410 if (!safe_read8 (signature, ptr, end))
1411 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1413 if (signature == 0x07) //FIXME implement localvarsig checking
1417 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1421 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1424 const char *ptr = NULL, *end;
1426 if (!decode_signature_header (ctx, offset, &size, &ptr))
1427 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
1430 return parse_property_signature (ctx, &ptr, end);
1434 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1436 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1437 //TODO do proper verification
1438 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1442 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1444 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1445 //TODO do proper verification
1446 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1450 is_valid_blob_object (VerifyContext *ctx, guint32 offset)
1452 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1453 guint32 entry_size, bytes;
1455 if (blob.size < offset) {
1460 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1463 if (offset + entry_size + bytes < offset)
1466 return blob.size >= offset + entry_size + bytes;
1470 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1472 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1473 guint32 size, entry_size, bytes;
1475 if (blob.size < offset) {
1481 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1484 if (type == MONO_TYPE_STRING) {
1485 //String is encoded as: compressed_int:len len *chars
1488 if (offset > offset + entry_size * 2) //overflow
1490 offset += offset + entry_size * 2;
1491 return offset <= blob.size;
1495 case MONO_TYPE_BOOLEAN:
1500 case MONO_TYPE_CHAR:
1508 case MONO_TYPE_CLASS:
1518 g_assert_not_reached ();
1521 if (size != entry_size)
1525 if(offset > offset + size) //overflow
1528 if (offset + size > blob.size)
1531 if (type == MONO_TYPE_CLASS && read32 (ctx->data + offset))
1537 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1539 //TODO do proper method header validation
1540 return mono_cli_rva_image_map (ctx->image, rva) != INVALID_ADDRESS;
1544 verify_module_table (VerifyContext *ctx)
1546 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1547 guint32 data [MONO_MODULE_SIZE];
1549 if (table->rows != 1)
1550 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1552 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1554 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1555 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1557 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1558 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1560 if (data [MONO_MODULE_ENC] != 0)
1561 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1563 if (data [MONO_MODULE_ENCBASE] != 0)
1564 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1568 verify_typeref_table (VerifyContext *ctx)
1570 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1571 guint32 data [MONO_TYPEREF_SIZE];
1574 for (i = 0; i < table->rows; ++i) {
1575 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1576 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1577 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1579 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1580 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1582 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1583 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1585 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1586 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
1590 /*bits 9,11,14,15,19,21,24-31 */
1591 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
1593 verify_typedef_table (VerifyContext *ctx)
1595 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1596 guint32 data [MONO_TYPEDEF_SIZE];
1597 guint32 fieldlist = 1, methodlist = 1;
1600 if (table->rows == 0)
1601 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
1603 for (i = 0; i < table->rows; ++i) {
1604 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
1605 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
1606 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
1608 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
1609 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
1611 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
1612 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1614 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
1615 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1617 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
1618 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
1620 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1621 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
1624 if (data [MONO_TYPEDEF_EXTENDS] != 0)
1625 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
1627 if (typedef_is_system_object (ctx, data) && data [MONO_TYPEDEF_EXTENDS] != 0)
1628 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
1630 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
1631 if (data [MONO_TYPEDEF_EXTENDS])
1632 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
1633 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
1634 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
1636 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1637 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
1639 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1640 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
1644 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
1645 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
1647 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
1648 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
1650 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
1651 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));
1653 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
1654 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
1656 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
1657 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
1659 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
1660 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));
1663 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
1664 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
1669 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
1671 verify_field_table (VerifyContext *ctx)
1673 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
1674 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
1677 module_field_list = (guint32)-1;
1678 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1679 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1680 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
1683 for (i = 0; i < table->rows; ++i) {
1684 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
1685 flags = data [MONO_FIELD_FLAGS];
1687 if (flags & INVALID_FIELD_FLAG_BITS)
1688 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
1690 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
1691 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
1693 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
1694 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
1696 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
1697 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
1699 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
1700 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
1702 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
1703 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
1704 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
1706 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
1707 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1708 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1710 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
1711 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1712 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
1714 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
1715 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
1716 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1718 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
1719 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
1721 //TODO verify contant flag
1722 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
1723 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
1725 if (i + 1 < module_field_list) {
1726 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
1727 if (!(flags & FIELD_ATTRIBUTE_STATIC))
1728 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
1729 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
1730 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
1735 /*bits 6,8,9,10,11,13,14,15*/
1736 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
1738 verify_method_table (VerifyContext *ctx)
1740 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1741 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
1742 guint32 paramlist = 1;
1743 gboolean is_ctor, is_cctor;
1747 module_method_list = (guint32)-1;
1748 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1749 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1750 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
1753 for (i = 0; i < table->rows; ++i) {
1754 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
1755 rva = data [MONO_METHOD_RVA];
1756 implflags = data [MONO_METHOD_IMPLFLAGS];
1757 flags = data [MONO_METHOD_FLAGS];
1758 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
1759 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
1762 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
1763 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
1766 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
1768 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
1769 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
1771 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
1772 is_ctor = !strcmp (".ctor", name);
1773 is_cctor = !strcmp (".cctor", name);
1775 if ((is_ctor || is_cctor) &&
1776 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
1777 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
1779 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
1780 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
1782 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
1783 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1784 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
1785 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
1786 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
1789 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
1790 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
1792 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
1793 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
1795 //XXX no checks against cas stuff 10,11,12,13)
1797 //TODO check iface with .ctor (15,16)
1799 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
1800 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
1802 if (i + 1 < module_method_list) {
1803 if (!(flags & METHOD_ATTRIBUTE_STATIC))
1804 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
1805 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
1806 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
1807 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
1808 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
1811 //TODO check valuetype for synchronized
1813 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
1814 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
1816 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
1817 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
1819 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
1820 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1821 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
1823 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
1824 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
1826 //TODO check signature contents
1829 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
1830 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
1831 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
1832 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
1833 if (!is_valid_method_header (ctx, rva))
1834 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
1836 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1837 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
1840 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
1842 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
1843 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
1844 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
1846 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
1847 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
1849 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
1850 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
1852 if (data [MONO_METHOD_PARAMLIST] == 0)
1853 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
1855 if (data [MONO_METHOD_PARAMLIST] < paramlist)
1856 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));
1858 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
1859 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
1861 paramlist = data [MONO_METHOD_PARAMLIST];
1867 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
1869 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1870 guint32 row = *current_method;
1871 guint32 paramlist, tmp;
1874 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
1875 while (row < table->rows) {
1876 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
1877 if (tmp > paramlist) {
1878 *current_method = row;
1879 return tmp - paramlist;
1884 /*no more methods, all params apply to the last one*/
1885 *current_method = table->rows;
1890 #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))
1892 verify_param_table (VerifyContext *ctx)
1894 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
1895 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
1896 gboolean first_param = TRUE;
1899 remaining_params = get_next_param_count (ctx, ¤t_method);
1901 for (i = 0; i < table->rows; ++i) {
1902 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
1903 flags = data [MONO_PARAM_FLAGS];
1905 if (flags & INVALID_PARAM_FLAGS_BITS)
1906 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
1908 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
1909 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
1910 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
1912 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
1913 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
1916 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)
1917 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
1919 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
1920 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
1922 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
1923 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
1925 first_param = FALSE;
1926 sequence = data [MONO_PARAM_SEQUENCE];
1927 if (--remaining_params == 0) {
1928 remaining_params = get_next_param_count (ctx, ¤t_method);
1935 verify_interfaceimpl_table (VerifyContext *ctx)
1937 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
1938 guint32 data [MONO_INTERFACEIMPL_SIZE];
1941 for (i = 0; i < table->rows; ++i) {
1942 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
1943 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
1944 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
1946 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
1947 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
1949 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
1950 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
1955 verify_memberref_table (VerifyContext *ctx)
1957 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
1958 guint32 data [MONO_MEMBERREF_SIZE];
1961 for (i = 0; i < table->rows; ++i) {
1962 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
1964 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
1965 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
1967 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
1968 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
1970 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
1971 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
1973 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
1974 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
1979 verify_constant_table (VerifyContext *ctx)
1981 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
1982 guint32 data [MONO_CONSTANT_SIZE], type;
1985 for (i = 0; i < table->rows; ++i) {
1986 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
1987 type = data [MONO_CONSTANT_TYPE];
1989 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
1990 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
1992 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
1993 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
1995 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
1996 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
1998 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
1999 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2004 verify_cattr_table (VerifyContext *ctx)
2006 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2007 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2010 for (i = 0; i < table->rows; ++i) {
2011 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2013 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2014 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2016 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2017 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2019 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2020 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2026 verify_field_marshal_table (VerifyContext *ctx)
2028 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2029 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2032 for (i = 0; i < table->rows; ++i) {
2033 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2035 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2036 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2038 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2039 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2041 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2042 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2044 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2045 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2051 verify_decl_security_table (VerifyContext *ctx)
2053 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2054 guint32 data [MONO_DECL_SECURITY_SIZE];
2057 for (i = 0; i < table->rows; ++i) {
2058 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2060 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2061 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2063 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2064 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2066 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2067 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2069 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2070 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2076 verify_class_layout_table (VerifyContext *ctx)
2078 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2079 guint32 data [MONO_CLASS_LAYOUT_SIZE];
2082 for (i = 0; i < table->rows; ++i) {
2083 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2085 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2086 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2088 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2100 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2106 verify_field_layout_table (VerifyContext *ctx)
2108 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2109 guint32 data [MONO_FIELD_LAYOUT_SIZE];
2112 for (i = 0; i < table->rows; ++i) {
2113 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2115 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2116 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2121 verify_standalonesig_table (VerifyContext *ctx)
2123 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2124 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2127 for (i = 0; i < table->rows; ++i) {
2128 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2130 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2131 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2136 verify_eventmap_table (VerifyContext *ctx)
2138 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2139 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2142 for (i = 0; i < table->rows; ++i) {
2143 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2145 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2146 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2148 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2149 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2151 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2155 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2157 verify_event_table (VerifyContext *ctx)
2159 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2160 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2161 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2162 gboolean found_add, found_remove;
2165 for (i = 0; i < table->rows; ++i) {
2166 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2168 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2169 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2171 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2172 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2174 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2175 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2177 //check for Add and Remove
2178 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2179 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2181 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2183 //first we move to the first row for this event
2185 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2189 //now move forward looking for AddOn and RemoveOn rows
2190 found_add = found_remove = FALSE;
2191 while (idx < sema_table->rows) {
2192 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2193 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2195 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2197 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2198 found_remove = TRUE;
2199 if (found_add && found_remove)
2205 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2207 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2212 verify_propertymap_table (VerifyContext *ctx)
2214 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2215 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2218 for (i = 0; i < table->rows; ++i) {
2219 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2221 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2222 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2224 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2225 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2227 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2231 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2233 verify_property_table (VerifyContext *ctx)
2235 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2236 guint32 data [MONO_PROPERTY_SIZE];
2239 for (i = 0; i < table->rows; ++i) {
2240 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2242 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2243 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2245 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2246 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2248 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2249 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2251 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2252 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2253 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2259 verify_methodimpl_table (VerifyContext *ctx)
2261 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2262 guint32 data [MONO_METHODIMPL_SIZE];
2265 for (i = 0; i < table->rows; ++i) {
2266 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2268 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2269 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2271 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2272 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2274 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2275 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2277 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2278 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2280 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2281 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2286 verify_moduleref_table (VerifyContext *ctx)
2288 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2289 guint32 data [MONO_MODULEREF_SIZE];
2292 for (i = 0; i < table->rows; ++i) {
2293 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2295 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2296 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2301 verify_typespec_table (VerifyContext *ctx)
2303 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2304 guint32 data [MONO_TYPESPEC_SIZE];
2307 for (i = 0; i < table->rows; ++i) {
2308 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2310 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2311 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2315 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10))
2317 verify_implmap_table (VerifyContext *ctx)
2319 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2320 guint32 data [MONO_IMPLMAP_SIZE], cconv;
2323 for (i = 0; i < table->rows; ++i) {
2324 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2326 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2327 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2329 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2330 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2331 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2333 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2334 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2336 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2337 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2339 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2340 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2342 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2343 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2345 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULE].rows + 1)
2346 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2351 verify_fieldrva_table (VerifyContext *ctx)
2353 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2354 guint32 data [MONO_FIELD_RVA_SIZE];
2357 for (i = 0; i < table->rows; ++i) {
2358 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2360 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2361 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2363 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2364 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2368 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
2370 verify_assembly_table (VerifyContext *ctx)
2372 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2373 guint32 data [MONO_ASSEMBLY_SIZE], hash;
2376 if (table->rows > 1)
2377 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2379 for (i = 0; i < table->rows; ++i) {
2380 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2382 hash = data [MONO_ASSEMBLY_HASH_ALG];
2383 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2384 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2386 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2387 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2389 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY]))
2390 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2392 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2393 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2395 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2396 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2400 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2402 verify_assemblyref_table (VerifyContext *ctx)
2404 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2405 guint32 data [MONO_ASSEMBLYREF_SIZE];
2408 for (i = 0; i < table->rows; ++i) {
2409 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2411 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2412 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2414 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY]))
2415 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2417 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2418 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
2420 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
2421 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
2423 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE]))
2424 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
2428 #define INVALID_FILE_FLAGS_BITS ~(1)
2430 verify_file_table (VerifyContext *ctx)
2432 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
2433 guint32 data [MONO_FILE_SIZE];
2436 for (i = 0; i < table->rows; ++i) {
2437 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
2439 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
2440 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
2442 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
2443 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
2445 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE]))
2446 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
2450 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
2452 verify_exportedtype_table (VerifyContext *ctx)
2454 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
2455 guint32 data [MONO_EXP_TYPE_SIZE];
2458 for (i = 0; i < table->rows; ++i) {
2459 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
2461 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
2462 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
2464 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
2465 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
2467 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
2468 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
2470 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2471 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
2473 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2474 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
2476 /*nested type can't have a namespace*/
2477 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
2478 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
2482 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
2484 verify_manifest_resource_table (VerifyContext *ctx)
2486 MonoCLIImageInfo *iinfo = ctx->image->image_info;
2487 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2488 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
2489 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
2492 resources_size = ch->ch_resources.size;
2494 for (i = 0; i < table->rows; ++i) {
2495 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
2497 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
2498 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
2500 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
2501 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
2503 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
2504 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
2506 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
2507 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
2509 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2510 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2512 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
2513 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])));
2515 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
2516 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
2518 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
2519 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
2524 verify_nested_class_table (VerifyContext *ctx)
2526 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
2527 guint32 data [MONO_NESTED_CLASS_SIZE];
2530 for (i = 0; i < table->rows; ++i) {
2531 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
2533 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2534 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
2535 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2536 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2537 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
2538 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2542 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
2544 verify_generic_param_table (VerifyContext *ctx)
2546 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
2547 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
2548 int i, param_number = 0;
2550 for (i = 0; i < table->rows; ++i) {
2551 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
2553 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
2554 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
2556 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
2557 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
2559 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
2560 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
2562 token = data [MONO_GENERICPARAM_OWNER];
2564 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
2565 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
2567 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
2568 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
2570 if (token != last_token) {
2575 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
2576 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));
2583 verify_method_spec_table (VerifyContext *ctx)
2585 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
2586 guint32 data [MONO_METHODSPEC_SIZE];
2589 for (i = 0; i < table->rows; ++i) {
2590 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
2592 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2593 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
2595 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2596 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
2598 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
2599 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
2604 verify_generic_param_constraint_table (VerifyContext *ctx)
2606 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
2607 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
2610 for (i = 0; i < table->rows; ++i) {
2611 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
2613 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
2614 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
2616 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2617 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
2619 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2620 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
2625 verify_tables_data (VerifyContext *ctx)
2627 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
2628 guint32 size = 0, tables_offset;
2631 for (i = 0; i < 0x2D; ++i) {
2632 MonoTableInfo *table = &ctx->image->tables [i];
2634 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
2635 if (tmp_size < size) {
2643 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
2645 tables_offset = ctx->image->tables_base - ctx->data;
2646 if (!bounds_check_offset (&tables_area, tables_offset, size))
2647 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)));
2649 verify_module_table (ctx);
2651 verify_typeref_table (ctx);
2653 verify_typedef_table (ctx);
2655 verify_field_table (ctx);
2657 verify_method_table (ctx);
2659 verify_param_table (ctx);
2661 verify_interfaceimpl_table (ctx);
2663 verify_memberref_table (ctx);
2665 verify_constant_table (ctx);
2667 verify_cattr_table (ctx);
2669 verify_field_marshal_table (ctx);
2671 verify_decl_security_table (ctx);
2673 verify_class_layout_table (ctx);
2675 verify_field_layout_table (ctx);
2677 verify_standalonesig_table (ctx);
2679 verify_eventmap_table (ctx);
2681 verify_event_table (ctx);
2683 verify_propertymap_table (ctx);
2685 verify_property_table (ctx);
2687 verify_methodimpl_table (ctx);
2689 verify_moduleref_table (ctx);
2691 verify_typespec_table (ctx);
2693 verify_implmap_table (ctx);
2695 verify_fieldrva_table (ctx);
2697 verify_assembly_table (ctx);
2699 verify_assemblyref_table (ctx);
2701 verify_file_table (ctx);
2703 verify_exportedtype_table (ctx);
2705 verify_manifest_resource_table (ctx);
2707 verify_nested_class_table (ctx);
2709 verify_generic_param_table (ctx);
2711 verify_method_spec_table (ctx);
2713 verify_generic_param_constraint_table (ctx);
2717 mono_verifier_is_corlib (MonoImage *image)
2719 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
2720 TRUE : mono_security_core_clr_is_platform_image (image);
2722 return trusted_location && !strcmp ("mscorlib.dll", image->name);
2726 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
2728 memset (ctx, 0, sizeof (VerifyContext));
2730 ctx->report_error = error_list != NULL;
2732 ctx->size = image->raw_data_len;
2733 ctx->data = image->raw_data;
2734 ctx->is_corlib = mono_verifier_is_corlib (image);
2738 cleanup_context (VerifyContext *ctx, GSList **error_list)
2740 g_free (ctx->sections);
2742 *error_list = ctx->errors;
2744 mono_free_verify_list (ctx->errors);
2749 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2753 if (!mono_verifier_is_enabled_for_image (image))
2756 init_verify_context (&ctx, image, error_list);
2757 ctx.stage = STAGE_PE;
2759 verify_msdos_header (&ctx);
2761 verify_pe_header (&ctx);
2763 verify_pe_optional_header (&ctx);
2765 load_section_table (&ctx);
2767 load_data_directories (&ctx);
2769 verify_import_table (&ctx);
2771 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
2772 verify_resources_table (&ctx);
2775 return cleanup_context (&ctx, error_list);
2779 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2783 if (!mono_verifier_is_enabled_for_image (image))
2786 init_verify_context (&ctx, image, error_list);
2787 ctx.stage = STAGE_CLI;
2789 verify_cli_header (&ctx);
2791 verify_metadata_header (&ctx);
2793 verify_tables_schema (&ctx);
2796 return cleanup_context (&ctx, error_list);
2800 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2804 if (!mono_verifier_is_enabled_for_image (image))
2807 init_verify_context (&ctx, image, error_list);
2808 ctx.stage = STAGE_TABLES;
2810 verify_tables_data (&ctx);
2812 return cleanup_context (&ctx, error_list);
2816 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2822 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2828 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2832 #endif /* DISABLE_VERIFIER */