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>
26 #include <mono/utils/mono-error-internals.h>
27 #include <mono/utils/bsearch.h>
32 #ifndef DISABLE_VERIFIER
34 TODO add fail fast mode
35 TODO add PE32+ support
36 TODO verify the entry point RVA and content.
37 TODO load_section_table and load_data_directories must take PE32+ into account
38 TODO add section relocation support
39 TODO verify the relocation table, since we really don't use, no need so far.
40 TODO do full PECOFF resources verification
41 TODO verify in the CLI header entry point and resources
42 TODO implement null token typeref validation
43 TODO verify table wide invariants for typedef (sorting and uniqueness)
44 TODO implement proper authenticode data directory validation
45 TODO verify properties that require multiple tables to be valid
46 FIXME use subtraction based bounds checking to avoid overflows
47 FIXME get rid of metadata_streams and other fields from VerifyContext
50 #ifdef MONO_VERIFIER_DEBUG
51 #define VERIFIER_DEBUG(code) do { code; } while (0)
53 #define VERIFIER_DEBUG(code)
56 #define INVALID_OFFSET ((guint32)-1)
57 #define INVALID_ADDRESS 0xffffffff
67 RESOURCE_TABLE_IDX = 2,
68 CERTIFICATE_TABLE_IDX = 4,
69 RELOCATION_TABLE_IDX = 5,
83 #define INVALID_TABLE (0xFF)
84 /*format: number of bits, number of tables, tables{n. tables} */
85 const static unsigned char coded_index_desc[] = {
86 #define TYPEDEF_OR_REF_DESC (0)
93 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
100 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
108 MONO_TABLE_INTERFACEIMPL,
109 MONO_TABLE_MEMBERREF,
111 MONO_TABLE_DECLSECURITY,
114 MONO_TABLE_STANDALONESIG,
115 MONO_TABLE_MODULEREF,
118 MONO_TABLE_ASSEMBLYREF,
120 MONO_TABLE_EXPORTEDTYPE,
121 MONO_TABLE_MANIFESTRESOURCE,
122 MONO_TABLE_GENERICPARAM,
124 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
130 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
137 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
142 MONO_TABLE_MODULEREF,
146 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
152 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
156 MONO_TABLE_MEMBERREF,
158 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
164 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
168 MONO_TABLE_ASSEMBLYREF,
169 MONO_TABLE_EXPORTEDTYPE,
171 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
177 MONO_TABLE_MEMBERREF,
180 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
184 MONO_TABLE_MODULEREF,
185 MONO_TABLE_ASSEMBLYREF,
188 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
198 guint32 translated_offset;
210 guint32 rellocationsRVA;
211 guint16 numberOfRelocations;
226 gboolean report_error;
227 gboolean report_warning;
230 DataDirectory data_directories [16];
231 guint32 section_count;
232 SectionHeader *sections;
234 OffsetAndSize metadata_streams [5]; //offset from begin of the image
237 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
239 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
240 vinfo->info.status = __status; \
241 vinfo->info.message = ( __msg); \
242 vinfo->exception_type = (__exception); \
243 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
246 #define ADD_WARNING(__ctx, __msg) \
248 if ((__ctx)->report_warning) { \
249 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
250 (__ctx)->valid = 0; \
255 #define ADD_ERROR_NO_RETURN(__ctx, __msg) \
257 if ((__ctx)->report_error) \
258 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
259 (__ctx)->valid = 0; \
262 #define ADD_ERROR(__ctx, __msg) \
264 if ((__ctx)->report_error) \
265 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
266 (__ctx)->valid = 0; \
270 #define FAIL(__ctx, __msg) \
272 if ((__ctx)->report_error) \
273 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
274 (__ctx)->valid = 0; \
278 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
280 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
282 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
283 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
285 #if SIZEOF_VOID_P == 4
286 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
288 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
291 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
292 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
295 dword_align (const char *ptr)
297 #if SIZEOF_VOID_P == 8
298 return (const char *) (((guint64) (ptr + 3)) & ~3);
300 return (const char *) (((guint32) (ptr + 3)) & ~3);
305 add_from_mono_error (VerifyContext *ctx, MonoError *error)
307 if (mono_error_ok (error))
310 ADD_ERROR (ctx, g_strdup (mono_error_get_message (error)));
311 mono_error_cleanup (error);
315 pe_signature_offset (VerifyContext *ctx)
317 return read32 (ctx->data + 0x3c);
321 pe_header_offset (VerifyContext *ctx)
323 return read32 (ctx->data + 0x3c) + 4;
327 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
331 if (rva + size < rva) //overflow
334 if (ctx->stage > STAGE_PE) {
335 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
336 const int top = iinfo->cli_section_count;
337 MonoSectionTable *tables = iinfo->cli_section_tables;
340 for (i = 0; i < top; i++) {
341 guint32 base = tables->st_virtual_address;
342 guint32 end = base + tables->st_raw_data_size;
344 if (rva >= base && rva + size <= end)
347 /*if ((addr >= tables->st_virtual_address) &&
348 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
350 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
360 for (i = 0; i < ctx->section_count; ++i) {
361 guint32 base = ctx->sections [i].baseRVA;
362 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
363 if (rva >= base && rva + size <= end)
370 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
372 if (dir->translated_offset > offset)
374 if (dir->size < size)
376 return offset + size <= dir->translated_offset + dir->size;
380 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
382 if (off->offset > offset)
385 if (off->size < size)
388 return offset + size <= off->offset + off->size;
392 translate_rva (VerifyContext *ctx, guint32 rva)
396 if (ctx->stage > STAGE_PE)
397 return mono_cli_rva_image_map (ctx->image, rva);
402 for (i = 0; i < ctx->section_count; ++i) {
403 guint32 base = ctx->sections [i].baseRVA;
404 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
405 if (rva >= base && rva <= end) {
406 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
408 return res >= ctx->size ? INVALID_OFFSET : res;
412 return INVALID_OFFSET;
416 verify_msdos_header (VerifyContext *ctx)
420 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
421 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
422 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
423 lfanew = pe_signature_offset (ctx);
424 if (lfanew > ctx->size - 4)
425 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
429 verify_pe_header (VerifyContext *ctx)
431 guint32 offset = pe_signature_offset (ctx);
432 const char *pe_header = ctx->data + offset;
433 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
434 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
438 if (offset > ctx->size - 20)
439 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
440 if (read16 (pe_header) != 0x14c)
441 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
445 verify_pe_optional_header (VerifyContext *ctx)
447 guint32 offset = pe_header_offset (ctx);
448 guint32 header_size, file_alignment;
449 const char *pe_header = ctx->data + offset;
450 const char *pe_optional_header = pe_header + 20;
452 header_size = read16 (pe_header + 16);
455 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
456 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
458 if (offset > ctx->size - header_size || header_size > ctx->size)
459 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
461 if (read16 (pe_optional_header) == 0x10b) {
462 if (header_size != 224)
463 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
465 /* LAMESPEC MS plays around this value and ignore it during validation
466 if (read32 (pe_optional_header + 28) != 0x400000)
467 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
468 if (read32 (pe_optional_header + 32) != 0x2000)
469 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
470 file_alignment = read32 (pe_optional_header + 36);
471 if (file_alignment != 0x200 && file_alignment != 0x1000)
472 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
473 /* All the junk in the middle is irrelevant, specially for mono. */
474 if (read32 (pe_optional_header + 92) > 0x10)
475 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
477 if (read16 (pe_optional_header) == 0x20B)
478 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
480 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
485 load_section_table (VerifyContext *ctx)
488 SectionHeader *sections;
489 guint32 offset = pe_header_offset (ctx);
490 const char *ptr = ctx->data + offset;
491 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
493 offset += 244;/*FIXME, this constant is different under PE32+*/
496 if (num_sections * 40 > ctx->size - offset)
497 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
499 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
500 for (i = 0; i < num_sections; ++i) {
501 sections [i].size = read32 (ptr + 8);
502 sections [i].baseRVA = read32 (ptr + 12);
503 sections [i].baseOffset = read32 (ptr + 20);
504 sections [i].rellocationsRVA = read32 (ptr + 24);
505 sections [i].numberOfRelocations = read16 (ptr + 32);
509 ptr = ctx->data + offset; /*reset it to the beggining*/
510 for (i = 0; i < num_sections; ++i) {
511 guint32 raw_size, flags;
512 if (sections [i].baseOffset == 0)
513 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
514 if (sections [i].baseOffset >= ctx->size)
515 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
516 if (sections [i].size > ctx->size - sections [i].baseOffset)
517 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
519 raw_size = read32 (ptr + 16);
520 if (raw_size < sections [i].size)
521 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
523 if (raw_size > ctx->size - sections [i].baseOffset)
524 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
526 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
527 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
529 flags = read32 (ptr + 36);
530 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
531 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
532 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
539 is_valid_data_directory (int i)
541 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
542 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
546 load_data_directories (VerifyContext *ctx)
548 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
549 const char *ptr = ctx->data + offset;
552 for (i = 0; i < 16; ++i) {
553 guint32 rva = read32 (ptr);
554 guint32 size = read32 (ptr + 4);
556 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
557 if (i == CERTIFICATE_TABLE_IDX) {
561 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
562 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
564 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
565 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
567 ctx->data_directories [i].rva = rva;
568 ctx->data_directories [i].size = size;
569 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
575 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
577 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
580 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
583 guint32 hint_table_rva;
585 import_rva = translate_rva (ctx, import_rva);
586 g_assert (import_rva != INVALID_OFFSET);
588 hint_table_rva = read32 (ctx->data + import_rva);
589 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
590 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
592 hint_table_rva = translate_rva (ctx, hint_table_rva);
593 g_assert (hint_table_rva != INVALID_OFFSET);
594 ptr = ctx->data + hint_table_rva + 2;
596 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
597 char name[SIZE_OF_CORMAIN];
598 memcpy (name, ptr, SIZE_OF_CORMAIN);
599 name [SIZE_OF_CORMAIN - 1] = 0;
600 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
605 verify_import_table (VerifyContext *ctx)
607 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
608 guint32 offset = it.translated_offset;
609 const char *ptr = ctx->data + offset;
610 guint32 name_rva, ilt_rva, iat_rva;
612 g_assert (offset != INVALID_OFFSET);
615 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
617 ilt_rva = read32 (ptr);
618 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
619 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
621 name_rva = read32 (ptr + 12);
622 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
623 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
625 iat_rva = read32 (ptr + 16);
627 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
628 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
630 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
631 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));
635 name_rva = translate_rva (ctx, name_rva);
636 g_assert (name_rva != INVALID_OFFSET);
637 ptr = ctx->data + name_rva;
639 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
640 char name[SIZE_OF_MSCOREE];
641 memcpy (name, ptr, SIZE_OF_MSCOREE);
642 name [SIZE_OF_MSCOREE - 1] = 0;
643 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
648 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
653 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
657 verify_resources_table (VerifyContext *ctx)
659 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
661 guint16 named_entries, id_entries;
668 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));
670 offset = it.translated_offset;
671 ptr = ctx->data + offset;
673 g_assert (offset != INVALID_OFFSET);
675 named_entries = read16 (ptr + 12);
676 id_entries = read16 (ptr + 14);
678 if ((named_entries + id_entries) * 8 + 16 > it.size)
679 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));
681 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
682 if (named_entries || id_entries)
683 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
687 /*----------nothing from here on can use data_directory---*/
690 get_data_dir (VerifyContext *ctx, int idx)
692 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
693 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
697 res.rva = entry->rva;
698 res.size = entry->size;
699 res.translated_offset = translate_rva (ctx, res.rva);
704 verify_cli_header (VerifyContext *ctx)
706 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
712 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
715 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
717 offset = it.translated_offset;
718 ptr = ctx->data + offset;
720 g_assert (offset != INVALID_OFFSET);
722 if (read16 (ptr) != 72)
723 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
725 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
726 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
729 if (!read32 (ptr + 8) || !read32 (ptr + 12))
730 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
732 if ((read32 (ptr + 16) & ~0x0001000B) != 0)
733 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
736 for (i = 0; i < 6; ++i) {
737 guint32 rva = read32 (ptr);
738 guint32 size = read32 (ptr + 4);
740 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
741 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
746 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
751 pad4 (guint32 offset)
753 if (offset & 0x3) //pad to the next 4 byte boundary
754 offset = (offset & ~0x3) + 4;
759 verify_metadata_header (VerifyContext *ctx)
762 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
763 guint32 offset, section_count;
766 offset = it.translated_offset;
767 ptr = ctx->data + offset;
768 g_assert (offset != INVALID_OFFSET);
770 //build a directory entry for the metadata root
772 it.rva = read32 (ptr);
774 it.size = read32 (ptr);
775 it.translated_offset = offset = translate_rva (ctx, it.rva);
777 ptr = ctx->data + offset;
778 g_assert (offset != INVALID_OFFSET);
781 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
783 if (read32 (ptr) != 0x424A5342)
784 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
786 offset = pad4 (offset + 16 + read32 (ptr + 12));
788 if (!bounds_check_datadir (&it, offset, 4))
789 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));
791 ptr = ctx->data + offset; //move to streams header
793 section_count = read16 (ptr + 2);
794 if (section_count < 2)
795 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 2 streams (#~ and #GUID)"));
800 for (i = 0; i < section_count; ++i) {
801 guint32 stream_off, stream_size;
802 int string_size, stream_idx;
804 if (!bounds_check_datadir (&it, offset, 8))
805 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));
807 stream_off = it.translated_offset + read32 (ptr);
808 stream_size = read32 (ptr + 4);
810 if (!bounds_check_datadir (&it, stream_off, stream_size))
811 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
816 for (string_size = 0; string_size < 32; ++string_size) {
817 if (!bounds_check_datadir (&it, offset++, 1))
818 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
819 if (!ptr [string_size])
823 if (ptr [string_size])
824 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
826 if (!strncmp ("#Strings", ptr, 9))
827 stream_idx = STRINGS_STREAM;
828 else if (!strncmp ("#US", ptr, 4))
829 stream_idx = USER_STRINGS_STREAM;
830 else if (!strncmp ("#Blob", ptr, 6))
831 stream_idx = BLOB_STREAM;
832 else if (!strncmp ("#GUID", ptr, 6))
833 stream_idx = GUID_STREAM;
834 else if (!strncmp ("#~", ptr, 3))
835 stream_idx = TILDE_STREAM;
837 ADD_WARNING (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
838 offset = pad4 (offset);
839 ptr = ctx->data + offset;
843 if (ctx->metadata_streams [stream_idx].offset != 0)
844 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
846 ctx->metadata_streams [stream_idx].offset = stream_off;
847 ctx->metadata_streams [stream_idx].size = stream_size;
849 offset = pad4 (offset);
850 ptr = ctx->data + offset;
853 if (!ctx->metadata_streams [TILDE_STREAM].size)
854 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
855 if (!ctx->metadata_streams [GUID_STREAM].size)
856 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
860 verify_tables_schema (VerifyContext *ctx)
862 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
863 unsigned offset = tables_area.offset;
864 const char *ptr = ctx->data + offset;
865 guint64 valid_tables;
869 if (tables_area.size < 24)
870 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
872 if (ptr [4] != 2 && ptr [4] != 1)
873 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
875 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
877 if ((ptr [6] & ~0x7) != 0)
878 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]));
880 valid_tables = read64 (ptr + 8);
882 for (i = 0; i < 64; ++i) {
883 if (!(valid_tables & ((guint64)1 << i)))
886 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
887 Unused: 0x1E 0x1F 0x2D-0x3F
888 We don't care about the MS extensions.*/
889 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
890 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i));
891 if (i == 0x1E || i == 0x1F || i >= 0x2D)
892 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
896 if (tables_area.size < 24 + count * 4)
897 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));
900 for (i = 0; i < 64; ++i) {
901 if (valid_tables & ((guint64)1 << i)) {
902 guint32 row_count = read32 (ptr);
903 if (row_count > (1 << 24) - 1)
904 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
910 /*----------nothing from here on can use data_directory or metadata_streams ---*/
913 get_col_offset (VerifyContext *ctx, int table, int column)
915 guint32 bitfield = ctx->image->tables [table].size_bitfield;
919 offset += mono_metadata_table_size (bitfield, column);
925 get_col_size (VerifyContext *ctx, int table, int column)
927 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
931 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
934 res.offset = header->data - ctx->data;
935 res.size = header->size;
941 is_valid_string_full_with_image (MonoImage *image, guint32 offset, gboolean allow_empty)
943 guint32 heap_offset = (char*)image->heap_strings.data - image->raw_data;
944 guint32 heap_size = image->heap_strings.size;
947 const char *data = image->raw_data + heap_offset;
949 if (offset >= heap_size)
951 if (CHECK_ADDP_OVERFLOW_UN (data, offset))
954 if (!mono_utf8_validate_and_len_with_bounds (data + offset, heap_size - offset, &length, NULL))
956 return allow_empty || length > 0;
961 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
963 return is_valid_string_full_with_image (ctx->image, offset, allow_empty);
967 is_valid_string (VerifyContext *ctx, guint32 offset)
969 return is_valid_string_full (ctx, offset, TRUE);
973 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
975 return is_valid_string_full (ctx, offset, FALSE);
979 is_valid_guid (VerifyContext *ctx, guint32 offset)
981 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
982 return guids.size >= 8 && guids.size - 8 >= offset;
986 get_coded_index_token (int token_kind, guint32 coded_token)
988 guint32 bits = coded_index_desc [token_kind];
989 return coded_token >> bits;
993 get_coded_index_table (int kind, guint32 coded_token)
995 guint32 idx, bits = coded_index_desc [kind];
997 idx = coded_token & ((1 << bits) - 1);
998 return coded_index_desc [kind + idx];
1002 make_coded_token (int kind, guint32 table, guint32 table_idx)
1004 guint32 bits = coded_index_desc [kind++];
1005 guint32 tables = coded_index_desc [kind++];
1007 for (i = 0; i < tables; ++i) {
1008 if (coded_index_desc [kind++] == table)
1009 return ((table_idx + 1) << bits) | i;
1011 g_assert_not_reached ();
1016 is_valid_coded_index_with_image (MonoImage *image, int token_kind, guint32 coded_token)
1018 guint32 bits = coded_index_desc [token_kind++];
1019 guint32 table_count = coded_index_desc [token_kind++];
1020 guint32 table = coded_token & ((1 << bits) - 1);
1021 guint32 token = coded_token >> bits;
1023 if (table >= table_count)
1026 /*token_kind points to the first table idx*/
1027 table = coded_index_desc [token_kind + table];
1029 if (table == INVALID_TABLE)
1031 return token <= image->tables [table].rows;
1035 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
1037 return is_valid_coded_index_with_image (ctx->image, token_kind, coded_token);
1044 MonoTableInfo *table;
1048 token_locator (const void *a, const void *b)
1050 RowLocator *loc = (RowLocator *)a;
1051 unsigned const char *row = (unsigned const char *)b;
1052 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1054 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1055 return (int)loc->token - (int)token;
1059 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1061 MonoTableInfo *tinfo = &ctx->image->tables [table];
1063 const char *res, *base;
1064 locator.token = coded_token;
1065 locator.col_offset = get_col_offset (ctx, table, column);
1066 locator.col_size = get_col_size (ctx, table, column);
1067 locator.table = tinfo;
1071 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) );
1072 res = (const char *)mono_binary_search (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1076 return (res - base) / tinfo->row_size;
1079 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1081 get_string_ptr (VerifyContext *ctx, guint offset)
1083 return ctx->image->heap_strings.data + offset;
1086 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1088 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1091 return strcmp (str, "");
1093 return strcmp (str, get_string_ptr (ctx, offset));
1097 mono_verifier_is_corlib (MonoImage *image)
1099 gboolean trusted_location = !mono_security_core_clr_enabled () ?
1100 TRUE : mono_security_core_clr_is_platform_image (image);
1102 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1106 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1108 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1112 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1115 const unsigned char *ptr = (const unsigned char *)_ptr;
1123 if ((b & 0x80) == 0) {
1126 } else if ((b & 0x40) == 0) {
1130 *value = ((b & 0x3f) << 8 | ptr [1]);
1135 *value = ((b & 0x1f) << 24) |
1145 decode_signature_header (VerifyContext *ctx, guint32 offset, guint32 *size, const char **first_byte)
1147 MonoStreamHeader blob = ctx->image->heap_blob;
1148 guint32 value, enc_size;
1150 if (offset >= blob.size)
1153 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1156 if (CHECK_ADD4_OVERFLOW_UN (offset, enc_size))
1161 if (ADD_IS_GREATER_OR_OVF (offset, value, blob.size))
1165 *first_byte = blob.data + offset;
1170 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1172 const char *ptr = *_ptr;
1173 if (ptr + size > limit)
1177 *dest = *((guint8*)ptr);
1181 *dest = read16 (ptr);
1185 *dest = read32 (ptr);
1194 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1197 const char *ptr = *_ptr;
1198 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1203 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1204 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1205 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1206 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1209 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1212 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1215 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1217 const char *ptr = *_ptr;
1222 if (!safe_read8 (type, ptr, end))
1223 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1225 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1230 if (!safe_read_cint (token, ptr, end))
1231 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1233 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1234 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1242 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1244 const char *ptr = *_ptr;
1246 unsigned size, num, i;
1248 if (!safe_read8 (val, ptr, end))
1249 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1252 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1254 if (!safe_read_cint (size, ptr, end))
1255 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1257 for (i = 0; i < size; ++i) {
1258 if (!safe_read_cint (num, ptr, end))
1259 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1262 if (!safe_read_cint (size, ptr, end))
1263 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1265 for (i = 0; i < size; ++i) {
1266 if (!safe_read_cint (num, ptr, end))
1267 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1275 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1277 const char *ptr = *_ptr;
1279 unsigned count, token, i;
1281 if (!safe_read8 (type, ptr, end))
1282 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1284 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1285 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1287 if (!safe_read_cint (token, ptr, end))
1288 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1290 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1291 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1294 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1295 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1296 FAIL (ctx, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx->token));
1299 if (!safe_read_cint (count, ptr, end))
1300 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1303 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1305 for (i = 0; i < count; ++i) {
1306 if (!parse_custom_mods (ctx, &ptr, end))
1307 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1309 if (!parse_type (ctx, &ptr, end))
1310 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1317 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1319 const char *ptr = *_ptr;
1323 if (!safe_read8 (type, ptr, end))
1324 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1326 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1327 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1328 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1329 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1330 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1334 if (!parse_custom_mods (ctx, &ptr, end))
1335 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1337 if (!safe_read8 (type, ptr, end))
1338 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1340 if (type != MONO_TYPE_VOID) {
1342 if (!parse_type (ctx, &ptr, end))
1343 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1347 case MONO_TYPE_VALUETYPE:
1348 case MONO_TYPE_CLASS:
1349 if (!safe_read_cint (token, ptr, end))
1350 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1352 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1353 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1355 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1356 FAIL (ctx, g_strdup_printf ("Type: zero TypeDefOrRef token %x", token));
1358 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1359 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1360 FAIL (ctx, g_strdup_printf ("Type: Recursive type specification (%x). A type signature can't reference itself", ctx->token));
1365 case MONO_TYPE_MVAR:
1366 if (!safe_read_cint (token, ptr, end))
1367 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1370 case MONO_TYPE_ARRAY:
1371 if (!parse_type (ctx, &ptr, end))
1372 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1373 if (!parse_array_shape (ctx, &ptr, end))
1374 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1377 case MONO_TYPE_GENERICINST:
1378 if (!parse_generic_inst (ctx, &ptr, end))
1379 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1382 case MONO_TYPE_FNPTR:
1383 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1384 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1387 case MONO_TYPE_SZARRAY:
1388 if (!parse_custom_mods (ctx, &ptr, end))
1389 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1390 if (!parse_type (ctx, &ptr, end))
1391 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1399 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1404 if (!parse_custom_mods (ctx, _ptr, end))
1408 if (!safe_read8 (type, ptr, end))
1409 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1411 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1416 //it's a byref, update the cursor ptr
1417 if (type == MONO_TYPE_BYREF)
1420 return parse_type (ctx, _ptr, end);
1424 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1429 if (!parse_custom_mods (ctx, _ptr, end))
1433 if (!safe_read8 (type, ptr, end))
1434 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1436 if (type == MONO_TYPE_TYPEDBYREF) {
1441 //it's a byref, update the cursor ptr
1442 if (type == MONO_TYPE_BYREF) {
1444 if (!parse_custom_mods (ctx, _ptr, end))
1448 return parse_type (ctx, _ptr, end);
1452 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1455 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1456 const char *ptr = *_ptr;
1457 gboolean saw_sentinel = FALSE;
1459 if (!safe_read8 (cconv, ptr, end))
1460 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1463 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1465 if (allow_unmanaged) {
1466 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1467 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1468 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1469 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1471 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1472 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1474 if ((cconv & 0x10) && gparam_count == 0)
1475 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1477 if (allow_unmanaged && (cconv & 0x10))
1478 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1480 if (!safe_read_cint (param_count, ptr, end))
1481 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1483 if (!parse_return_type (ctx, &ptr, end))
1484 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1486 for (i = 0; i < param_count; ++i) {
1487 if (allow_sentinel) {
1488 if (!safe_read8 (type, ptr, end))
1489 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1491 if (type == MONO_TYPE_SENTINEL) {
1492 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1493 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1496 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1498 saw_sentinel = TRUE;
1504 if (!parse_param (ctx, &ptr, end))
1505 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1513 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1516 unsigned param_count = 0, i;
1517 const char *ptr = *_ptr;
1519 if (!safe_read8 (sig, ptr, end))
1520 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1522 if (sig != 0x08 && sig != 0x28)
1523 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1525 if (!safe_read_cint (param_count, ptr, end))
1526 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1528 if (!parse_custom_mods (ctx, &ptr, end))
1531 if (!parse_type (ctx, &ptr, end))
1532 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1534 for (i = 0; i < param_count; ++i) {
1535 if (!parse_custom_mods (ctx, &ptr, end))
1536 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1537 if (!parse_type (ctx, &ptr, end))
1538 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1546 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1548 const char *ptr = *_ptr;
1549 unsigned signature = 0;
1551 if (!safe_read8 (signature, ptr, end))
1552 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1554 if (signature != 0x06)
1555 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1557 if (!parse_custom_mods (ctx, &ptr, end))
1560 if (safe_read8 (signature, ptr, end)) {
1561 if (signature != MONO_TYPE_BYREF)
1566 return parse_type (ctx, _ptr, end);
1570 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1573 unsigned locals_count = 0, i;
1574 const char *ptr = *_ptr;
1576 if (!safe_read8 (sig, ptr, end))
1577 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1580 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1582 if (!safe_read_cint (locals_count, ptr, end))
1583 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1585 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1586 if (locals_count == 0)
1587 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1590 for (i = 0; i < locals_count; ++i) {
1591 if (!safe_read8 (sig, ptr, end))
1592 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1594 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1595 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1596 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1597 if (!safe_read8 (sig, ptr, end))
1598 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1601 if (sig == MONO_TYPE_BYREF) {
1602 if (!safe_read8 (sig, ptr, end))
1603 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1604 if (sig == MONO_TYPE_TYPEDBYREF)
1605 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1608 if (sig == MONO_TYPE_TYPEDBYREF)
1613 if (!parse_type (ctx, &ptr, end))
1614 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1622 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1625 unsigned signature = 0;
1626 const char *ptr = NULL, *end;
1628 if (!decode_signature_header (ctx, offset, &size, &ptr))
1629 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1632 if (!safe_read8 (signature, ptr, end))
1633 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1636 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1639 return parse_field (ctx, &ptr, end);
1643 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1646 const char *ptr = NULL, *end;
1648 if (!decode_signature_header (ctx, offset, &size, &ptr))
1649 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1652 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1656 is_valid_memberref_method_signature (VerifyContext *ctx, guint32 offset)
1659 const char *ptr = NULL, *end;
1661 if (!decode_signature_header (ctx, offset, &size, &ptr))
1662 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1665 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1670 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1673 unsigned signature = 0;
1674 const char *ptr = NULL, *end;
1676 if (!decode_signature_header (ctx, offset, &size, &ptr))
1677 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1680 if (!safe_read8 (signature, ptr, end))
1681 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1684 if (signature == 0x06)
1685 return parse_field (ctx, &ptr, end);
1687 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1691 is_valid_cattr_blob (VerifyContext *ctx, guint32 offset)
1694 unsigned prolog = 0;
1695 const char *ptr = NULL, *end;
1700 if (!decode_signature_header (ctx, offset, &size, &ptr))
1701 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1704 if (!safe_read16 (prolog, ptr, end))
1705 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1708 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1714 is_valid_cattr_type (MonoType *type)
1718 if (type->type == MONO_TYPE_OBJECT || (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_STRING))
1721 if (type->type == MONO_TYPE_VALUETYPE) {
1722 klass = mono_class_from_mono_type (type);
1723 return klass && klass->enumtype;
1726 if (type->type == MONO_TYPE_CLASS)
1727 return mono_class_from_mono_type (type) == mono_defaults.systemtype_class;
1733 is_valid_ser_string_full (VerifyContext *ctx, const char **str_start, guint32 *str_len, const char **_ptr, const char *end)
1736 const char *ptr = *_ptr;
1742 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1745 if (*ptr == (char)0xFF) {
1750 if (!safe_read_cint (size, ptr, end))
1751 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1753 if (ADDP_IS_GREATER_OR_OVF (ptr, size, end))
1754 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string"));
1764 is_valid_ser_string (VerifyContext *ctx, const char **_ptr, const char *end)
1766 const char *dummy_str;
1768 return is_valid_ser_string_full (ctx, &dummy_str, &dummy_int, _ptr, end);
1772 get_enum_by_encoded_name (VerifyContext *ctx, const char **_ptr, const char *end)
1776 const char *str_start = NULL;
1777 const char *ptr = *_ptr;
1779 guint32 str_len = 0;
1781 if (!is_valid_ser_string_full (ctx, &str_start, &str_len, &ptr, end))
1784 /*NULL or empty string*/
1785 if (str_start == NULL || str_len == 0) {
1786 ADD_ERROR_NO_RETURN (ctx, g_strdup ("CustomAttribute: Null or empty enum name"));
1790 enum_name = (char *)g_memdup (str_start, str_len + 1);
1791 enum_name [str_len] = 0;
1792 type = mono_reflection_type_from_name (enum_name, ctx->image);
1794 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid enum class %s", enum_name));
1800 klass = mono_class_from_mono_type (type);
1801 if (!klass || !klass->enumtype) {
1802 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute:Class %s::%s is not an enum", klass->name_space, klass->name));
1811 is_valid_fixed_param (VerifyContext *ctx, MonoType *mono_type, const char **_ptr, const char *end)
1814 const char *ptr = *_ptr;
1816 guint32 element_count, i;
1819 klass = mono_type->data.klass;
1820 type = mono_type->type;
1824 case MONO_TYPE_BOOLEAN:
1831 case MONO_TYPE_CHAR:
1845 case MONO_TYPE_STRING:
1847 return is_valid_ser_string (ctx, _ptr, end);
1849 case MONO_TYPE_OBJECT: {
1850 unsigned sub_type = 0;
1851 if (!safe_read8 (sub_type, ptr, end))
1852 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array type"));
1854 if (sub_type >= MONO_TYPE_BOOLEAN && sub_type <= MONO_TYPE_STRING) {
1858 if (sub_type == MONO_TYPE_ENUM) {
1859 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1863 klass = klass->element_class;
1864 type = klass->byval_arg.type;
1867 if (sub_type == 0x50) { /*Type*/
1869 return is_valid_ser_string (ctx, _ptr, end);
1871 if (sub_type == MONO_TYPE_SZARRAY) {
1872 MonoType simple_type = {{0}};
1874 if (!safe_read8 (etype, ptr, end))
1875 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1877 if (etype == MONO_TYPE_ENUM) {
1878 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1881 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
1882 klass = mono_defaults.systemtype_class;
1883 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1884 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : (MonoTypeEnum)etype;
1885 klass = mono_class_from_mono_type (&simple_type);
1887 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1889 type = MONO_TYPE_SZARRAY;
1892 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type));
1896 case MONO_TYPE_CLASS:
1897 if (klass != mono_defaults.systemtype_class)
1898 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1900 return is_valid_ser_string (ctx, _ptr, end);
1902 case MONO_TYPE_VALUETYPE:
1903 if (!klass || !klass->enumtype)
1904 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass->name_space, klass->name));
1906 klass = klass->element_class;
1907 type = klass->byval_arg.type;
1910 case MONO_TYPE_SZARRAY:
1911 mono_type = &klass->byval_arg;
1912 if (!is_valid_cattr_type (mono_type))
1913 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass->name_space, klass->name));
1914 if (!safe_read32 (element_count, ptr, end))
1915 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1916 if (element_count == 0xFFFFFFFFu) {
1920 for (i = 0; i < element_count; ++i) {
1921 if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
1927 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
1930 if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
1931 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
1932 *_ptr = ptr + elem_size;
1937 is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
1940 unsigned prolog = 0;
1942 MonoMethodSignature *sig;
1947 FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
1949 sig = mono_method_signature_checked (ctor, &error);
1950 if (!mono_error_ok (&error)) {
1951 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error)));
1952 mono_error_cleanup (&error);
1956 if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
1957 FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1961 if (!safe_read16 (prolog, ptr, end))
1962 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1965 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1967 args = sig->param_count;
1968 for (i = 0; i < args; ++i) {
1969 MonoType *arg_type = sig->params [i];
1970 if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
1974 if (!safe_read16 (num_named, ptr, end))
1975 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
1977 for (i = 0; i < num_named; ++i) {
1978 MonoType *type, simple_type = {{0}};
1981 if (!safe_read8 (kind, ptr, end))
1982 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
1983 if (kind != 0x53 && kind != 0x54)
1984 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
1985 if (!safe_read8 (kind, ptr, end))
1986 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
1988 if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
1989 simple_type.type = (MonoTypeEnum)kind;
1990 type = &simple_type;
1991 } else if (kind == MONO_TYPE_ENUM) {
1992 MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
1995 type = &klass->byval_arg;
1996 } else if (kind == 0x50) {
1997 type = &mono_defaults.systemtype_class->byval_arg;
1998 } else if (kind == 0x51) {
1999 type = &mono_defaults.object_class->byval_arg;
2000 } else if (kind == MONO_TYPE_SZARRAY) {
2003 if (!safe_read8 (etype, ptr, end))
2004 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
2006 if (etype == MONO_TYPE_ENUM) {
2007 klass = get_enum_by_encoded_name (ctx, &ptr, end);
2010 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
2011 klass = mono_defaults.systemtype_class;
2012 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
2013 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : (MonoTypeEnum)etype;
2014 klass = mono_class_from_mono_type (&simple_type);
2016 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
2018 type = &mono_array_class_get (klass, 1)->byval_arg;
2020 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
2023 if (!is_valid_ser_string (ctx, &ptr, end))
2026 if (!is_valid_fixed_param (ctx, type, &ptr, end))
2035 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
2037 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2038 //TODO do proper verification
2039 return blob.size >= 1 && blob.size - 1 >= offset;
2043 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
2045 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2046 //TODO do proper verification
2047 return blob.size >= 1 && blob.size - 1 >= offset;
2051 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
2054 unsigned signature = 0;
2055 const char *ptr = NULL, *end;
2057 if (!decode_signature_header (ctx, offset, &size, &ptr))
2058 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
2061 if (!safe_read8 (signature, ptr, end))
2062 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2065 if (signature == 0x07)
2066 return parse_locals_signature (ctx, &ptr, end);
2068 /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
2069 if (signature == 0x06)
2070 return parse_field (ctx, &ptr, end);
2072 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
2076 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
2079 const char *ptr = NULL, *end;
2081 if (!decode_signature_header (ctx, offset, &size, &ptr))
2082 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
2085 return parse_property_signature (ctx, &ptr, end);
2089 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
2092 const char *ptr = NULL, *end;
2095 if (!decode_signature_header (ctx, offset, &size, &ptr))
2096 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
2099 if (!parse_custom_mods (ctx, &ptr, end))
2102 if (!safe_read8 (type, ptr, end))
2103 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
2105 if (type == MONO_TYPE_BYREF) {
2106 if (!safe_read8 (type, ptr, end))
2107 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
2108 if (type == MONO_TYPE_TYPEDBYREF)
2109 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
2112 if (type == MONO_TYPE_TYPEDBYREF)
2116 return parse_type (ctx, &ptr, end);
2120 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
2123 const char *ptr = NULL, *end;
2125 unsigned count = 0, i;
2127 if (!decode_signature_header (ctx, offset, &size, &ptr))
2128 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
2131 if (!safe_read8 (type, ptr, end))
2132 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
2135 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
2137 if (!safe_read_cint (count, ptr, end))
2138 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
2141 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
2143 for (i = 0; i < count; ++i) {
2144 if (!parse_custom_mods (ctx, &ptr, end))
2146 if (!parse_type (ctx, &ptr, end))
2147 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
2153 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
2155 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2156 guint32 entry_size, bytes;
2158 if (blob.size < offset)
2161 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2164 if (entry_size < minsize)
2167 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
2169 entry_size += bytes;
2171 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
2175 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
2177 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2178 guint32 size, entry_size, bytes;
2180 if (blob.size < offset)
2181 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
2183 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2184 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
2186 if (type == MONO_TYPE_STRING) {
2187 //String is encoded as: compressed_int:len len *bytes
2190 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
2191 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
2197 case MONO_TYPE_BOOLEAN:
2202 case MONO_TYPE_CHAR:
2210 case MONO_TYPE_CLASS:
2220 g_assert_not_reached ();
2223 if (size != entry_size)
2224 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
2228 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
2229 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
2231 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
2232 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
2236 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
2237 //only 0x01, 0x40 and 0x80 are allowed
2238 #define SECTION_HEADER_INVALID_FLAGS 0x3E
2241 is_valid_method_header (VerifyContext *ctx, guint32 rva, guint32 *locals_token)
2243 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
2244 unsigned header = 0;
2245 unsigned fat_header = 0, size = 0, max_stack;
2246 const char *ptr = NULL, *end;
2250 if (offset == INVALID_ADDRESS)
2251 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
2253 ptr = ctx->data + offset;
2254 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
2256 if (!safe_read8 (header, ptr, end))
2257 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
2259 switch (header & 0x3) {
2262 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
2265 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
2266 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
2271 if (!safe_read16 (fat_header, ptr, end))
2272 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
2274 size = (fat_header >> 12) & 0xF;
2276 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
2278 if (!safe_read16 (max_stack, ptr, end))
2279 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
2281 if (!safe_read32 (code_size, ptr, end))
2282 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
2284 if (!safe_read32 (local_vars_tok, ptr, end))
2285 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
2287 if (local_vars_tok) {
2288 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
2289 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
2290 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
2291 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
2292 if (!(local_vars_tok & 0xFFFFFF))
2293 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature with zero index"));
2294 *locals_token = local_vars_tok & 0xFFFFFF;
2297 if (fat_header & FAT_HEADER_INVALID_FLAGS)
2298 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
2300 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
2301 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
2303 if (!(fat_header & 0x08))
2309 unsigned section_header = 0, section_size = 0;
2312 ptr = dword_align (ptr);
2313 if (!safe_read32 (section_header, ptr, end))
2314 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
2316 if (section_header & SECTION_HEADER_INVALID_FLAGS)
2317 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
2319 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
2320 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
2322 if (section_size < 4)
2323 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
2325 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
2326 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
2328 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
2329 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
2331 LAMEIMPL: MS emits section_size without accounting for header size.
2332 Mono does as the spec says. section_size is header + section
2333 MS's peverify happily accepts both.
2335 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
2336 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid EH section size %d, it's not of the expected size %d", section_size, clauses * (is_fat ? 24 : 12)));
2338 /* only verify the class token is verified as the rest is done by the IL verifier*/
2339 for (i = 0; i < clauses; ++i) {
2340 unsigned flags = *(unsigned char*)ptr;
2341 unsigned class_token = 0;
2342 ptr += (is_fat ? 20 : 8);
2343 if (!safe_read32 (class_token, ptr, end))
2344 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
2345 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
2346 guint table = mono_metadata_token_table (class_token);
2347 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
2348 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
2349 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
2350 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
2355 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
2362 verify_module_table (VerifyContext *ctx)
2364 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
2365 guint32 data [MONO_MODULE_SIZE];
2367 if (table->rows != 1)
2368 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
2370 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
2372 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
2373 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
2375 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
2376 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
2378 if (data [MONO_MODULE_ENC] != 0)
2379 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
2381 if (data [MONO_MODULE_ENCBASE] != 0)
2382 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
2386 verify_typeref_table (VerifyContext *ctx)
2388 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2392 for (i = 0; i < table->rows; ++i) {
2393 mono_verifier_verify_typeref_row (ctx->image, i, &error);
2394 add_from_mono_error (ctx, &error);
2398 /*bits 9,11,14,15,19,21,24-31 */
2399 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2401 verify_typedef_table (VerifyContext *ctx)
2403 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2404 guint32 data [MONO_TYPEDEF_SIZE];
2405 guint32 fieldlist = 1, methodlist = 1, visibility;
2408 if (table->rows == 0)
2409 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2411 for (i = 0; i < table->rows; ++i) {
2412 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2413 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2414 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2416 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2417 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2419 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2420 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2422 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2423 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2425 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2426 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2428 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2429 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2431 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2432 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2434 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2435 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2437 if (data [MONO_TYPEDEF_EXTENDS] && !get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2438 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d zero coded extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2440 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2441 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2442 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2443 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2445 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2446 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2448 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2449 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2451 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2452 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));
2454 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2455 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2457 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2458 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2460 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2461 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));
2463 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2464 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2469 verify_typedef_table_full (VerifyContext *ctx)
2471 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2472 guint32 data [MONO_TYPEDEF_SIZE];
2475 if (table->rows == 0)
2476 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2478 for (i = 0; i < table->rows; ++i) {
2479 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2482 /*XXX it's ok if <module> extends object, or anything at all, actually. */
2483 /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
2484 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2489 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2490 if (data [MONO_TYPEDEF_EXTENDS])
2491 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2493 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2494 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2498 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2501 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2509 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2511 verify_field_table (VerifyContext *ctx)
2513 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2514 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2517 module_field_list = (guint32)-1;
2518 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2519 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2520 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2523 for (i = 0; i < table->rows; ++i) {
2524 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2525 flags = data [MONO_FIELD_FLAGS];
2527 if (flags & INVALID_FIELD_FLAG_BITS)
2528 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2530 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2531 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2533 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2534 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2536 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2537 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2539 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2540 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2542 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2543 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2544 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2546 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2547 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2548 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2550 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2551 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2552 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2554 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2555 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2556 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2558 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2559 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2561 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2562 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2564 //TODO verify contant flag
2566 if (i + 1 < module_field_list) {
2567 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2568 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2569 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2570 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2571 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2577 verify_field_table_full (VerifyContext *ctx)
2579 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2580 guint32 data [MONO_FIELD_SIZE];
2583 for (i = 0; i < table->rows; ++i) {
2584 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2586 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2587 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2591 /*bits 8,9,10,11,13,14,15*/
2592 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2594 verify_method_table (VerifyContext *ctx)
2596 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2597 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2598 guint32 paramlist = 1;
2599 gboolean is_ctor, is_cctor;
2603 module_method_list = (guint32)-1;
2604 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2605 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2606 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2609 for (i = 0; i < table->rows; ++i) {
2610 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2611 rva = data [MONO_METHOD_RVA];
2612 implflags = data [MONO_METHOD_IMPLFLAGS];
2613 flags = data [MONO_METHOD_FLAGS];
2614 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2615 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2618 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2619 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2622 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2624 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2625 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2627 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2628 is_ctor = !strcmp (".ctor", name);
2629 is_cctor = !strcmp (".cctor", name);
2631 if ((is_ctor || is_cctor) &&
2632 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2633 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2635 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2636 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2638 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2639 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2640 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2641 if (flags & METHOD_ATTRIBUTE_FINAL)
2642 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2643 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2644 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2647 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2648 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2650 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2651 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2653 //XXX no checks against cas stuff 10,11,12,13)
2655 //TODO check iface with .ctor (15,16)
2657 if (i + 1 < module_method_list) {
2658 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2659 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2660 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2661 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2662 if (access == METHOD_ATTRIBUTE_FAMILY || access == METHOD_ATTRIBUTE_FAM_AND_ASSEM || access == METHOD_ATTRIBUTE_FAM_OR_ASSEM)
2663 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public, Private or Assembly", i));
2666 //TODO check valuetype for synchronized
2668 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2669 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2671 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2672 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2673 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2674 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2675 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2678 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2679 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2680 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2682 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2683 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2685 //TODO check signature contents
2688 if ((flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) || (implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
2689 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is either Abstract, InternalCall or PinvokeImpl", i));
2690 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2691 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2693 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2694 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2697 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2699 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2700 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2701 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2703 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2704 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2706 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2707 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2709 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2710 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2712 if (data [MONO_METHOD_PARAMLIST] == 0)
2713 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2715 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2716 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));
2718 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2719 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2721 paramlist = data [MONO_METHOD_PARAMLIST];
2727 verify_method_table_full (VerifyContext *ctx)
2729 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2730 guint32 data [MONO_METHOD_SIZE], rva, locals_token;
2733 for (i = 0; i < table->rows; ++i) {
2734 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2735 rva = data [MONO_METHOD_RVA];
2737 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2738 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2740 if (rva && !is_valid_method_header (ctx, rva, &locals_token))
2741 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2746 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2748 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2749 guint32 row = *current_method;
2750 guint32 paramlist, tmp;
2753 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2754 while (row < table->rows) {
2755 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2756 if (tmp > paramlist) {
2757 *current_method = row;
2758 return tmp - paramlist;
2763 /*no more methods, all params apply to the last one*/
2764 *current_method = table->rows;
2769 #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))
2771 verify_param_table (VerifyContext *ctx)
2773 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2774 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2775 gboolean first_param = TRUE;
2778 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2779 if (table->rows > 0)
2780 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2784 remaining_params = get_next_param_count (ctx, ¤t_method);
2786 for (i = 0; i < table->rows; ++i) {
2787 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2788 flags = data [MONO_PARAM_FLAGS];
2790 if (flags & INVALID_PARAM_FLAGS_BITS)
2791 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2793 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2794 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2795 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2797 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2798 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2801 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)
2802 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2804 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2805 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2807 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2808 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2810 first_param = FALSE;
2811 sequence = data [MONO_PARAM_SEQUENCE];
2812 if (--remaining_params == 0) {
2813 remaining_params = get_next_param_count (ctx, ¤t_method);
2820 verify_interfaceimpl_table (VerifyContext *ctx)
2822 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2823 guint32 data [MONO_INTERFACEIMPL_SIZE];
2826 for (i = 0; i < table->rows; ++i) {
2827 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2828 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2829 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_INTERFACEIMPL_CLASS]));
2831 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2832 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2834 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2835 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2840 verify_memberref_table (VerifyContext *ctx)
2842 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2843 guint32 data [MONO_MEMBERREF_SIZE];
2846 for (i = 0; i < table->rows; ++i) {
2847 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2849 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2850 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2852 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2853 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2855 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2856 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2858 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2859 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2865 verify_memberref_table_full (VerifyContext *ctx)
2867 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2868 guint32 data [MONO_MEMBERREF_SIZE];
2871 for (i = 0; i < table->rows; ++i) {
2872 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2874 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2875 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2880 verify_constant_table (VerifyContext *ctx)
2882 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2883 guint32 data [MONO_CONSTANT_SIZE], type;
2886 for (i = 0; i < table->rows; ++i) {
2887 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2888 type = data [MONO_CONSTANT_TYPE];
2890 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2891 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2893 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2894 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2896 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2897 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2899 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2900 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2905 verify_cattr_table (VerifyContext *ctx)
2907 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2908 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2911 for (i = 0; i < table->rows; ++i) {
2912 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2914 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2915 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2917 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]) || !get_coded_index_token (CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2918 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Type field 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2920 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2921 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2926 verify_cattr_table_full (VerifyContext *ctx)
2929 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2932 guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2935 for (i = 0; i < table->rows; ++i) {
2936 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2938 if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2939 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2941 mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2942 switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2943 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2944 mtoken |= MONO_TOKEN_METHOD_DEF;
2946 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2947 mtoken |= MONO_TOKEN_MEMBER_REF;
2950 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2953 ctor = mono_get_method_checked (ctx->image, mtoken, NULL, NULL, &error);
2956 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Could not load ctor due to %s", i, mono_error_get_message (&error)));
2957 mono_error_cleanup (&error);
2960 /*This can't fail since this is checked in is_valid_cattr_blob*/
2961 g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
2963 if (!is_valid_cattr_content (ctx, ctor, ptr, size))
2964 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2969 verify_field_marshal_table (VerifyContext *ctx)
2971 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2972 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2975 for (i = 0; i < table->rows; ++i) {
2976 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2978 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2979 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2981 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2982 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2984 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2985 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2987 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2988 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2993 verify_field_marshal_table_full (VerifyContext *ctx)
2995 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2996 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2999 for (i = 0; i < table->rows; ++i) {
3000 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
3002 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
3003 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
3008 verify_decl_security_table (VerifyContext *ctx)
3010 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3011 guint32 data [MONO_DECL_SECURITY_SIZE];
3014 for (i = 0; i < table->rows; ++i) {
3015 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3017 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3018 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
3020 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3021 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
3023 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
3024 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
3029 verify_decl_security_table_full (VerifyContext *ctx)
3031 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3032 guint32 data [MONO_DECL_SECURITY_SIZE];
3035 for (i = 0; i < table->rows; ++i) {
3036 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3038 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
3039 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
3044 verify_class_layout_table (VerifyContext *ctx)
3046 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
3047 guint32 data [MONO_CLASS_LAYOUT_SIZE];
3050 for (i = 0; i < table->rows; ++i) {
3051 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
3053 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3054 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
3056 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
3068 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3074 verify_field_layout_table (VerifyContext *ctx)
3076 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3077 guint32 data [MONO_FIELD_LAYOUT_SIZE];
3080 for (i = 0; i < table->rows; ++i) {
3081 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
3083 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3084 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
3089 verify_standalonesig_table (VerifyContext *ctx)
3091 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3092 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3095 for (i = 0; i < table->rows; ++i) {
3096 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3098 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
3099 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3104 verify_standalonesig_table_full (VerifyContext *ctx)
3106 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3107 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3110 for (i = 0; i < table->rows; ++i) {
3111 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3113 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
3114 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3119 verify_eventmap_table (VerifyContext *ctx)
3121 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3122 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3125 for (i = 0; i < table->rows; ++i) {
3126 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
3128 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3129 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
3131 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
3132 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
3134 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
3138 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3140 verify_event_table (VerifyContext *ctx)
3142 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3143 guint32 data [MONO_EVENT_SIZE];
3146 for (i = 0; i < table->rows; ++i) {
3147 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3149 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
3150 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
3152 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
3153 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
3155 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
3156 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
3161 verify_event_table_full (VerifyContext *ctx)
3163 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3164 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
3165 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
3166 gboolean found_add, found_remove;
3169 for (i = 0; i < table->rows; ++i) {
3170 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3172 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
3173 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
3175 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
3177 //first we move to the first row for this event
3179 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3183 //now move forward looking for AddOn and RemoveOn rows
3184 found_add = found_remove = FALSE;
3185 while (idx < sema_table->rows) {
3186 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
3187 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
3189 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3191 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3192 found_remove = TRUE;
3193 if (found_add && found_remove)
3199 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3201 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no RemoveOn associated method", i));
3206 verify_propertymap_table (VerifyContext *ctx)
3208 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3209 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3212 for (i = 0; i < table->rows; ++i) {
3213 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
3215 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3216 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
3218 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
3219 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
3221 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
3225 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3227 verify_property_table (VerifyContext *ctx)
3229 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3230 guint32 data [MONO_PROPERTY_SIZE];
3233 for (i = 0; i < table->rows; ++i) {
3234 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
3236 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
3237 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
3239 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
3240 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
3242 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
3243 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
3245 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
3246 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
3247 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
3253 verify_methodimpl_table (VerifyContext *ctx)
3255 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3256 guint32 data [MONO_METHODIMPL_SIZE];
3259 for (i = 0; i < table->rows; ++i) {
3260 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3262 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3263 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3265 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3266 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3268 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3269 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3271 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3272 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3274 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3275 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3280 verify_moduleref_table (VerifyContext *ctx)
3282 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3283 guint32 data [MONO_MODULEREF_SIZE];
3286 for (i = 0; i < table->rows; ++i) {
3287 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
3289 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
3290 ADD_ERROR (ctx, g_strdup_printf ("Invalid ModuleRef row %d name field %08x", i, data [MONO_MODULEREF_NAME]));
3295 verify_typespec_table (VerifyContext *ctx)
3297 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3298 guint32 data [MONO_TYPESPEC_SIZE];
3301 for (i = 0; i < table->rows; ++i) {
3302 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3304 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
3305 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3310 verify_typespec_table_full (VerifyContext *ctx)
3312 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3313 guint32 data [MONO_TYPESPEC_SIZE];
3316 for (i = 0; i < table->rows; ++i) {
3317 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3318 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
3319 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
3320 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3325 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 12) | (1 << 13))
3327 verify_implmap_table (VerifyContext *ctx)
3329 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3330 guint32 data [MONO_IMPLMAP_SIZE], cconv;
3333 for (i = 0; i < table->rows; ++i) {
3334 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
3336 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
3337 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
3339 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
3340 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
3341 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
3343 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3344 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
3346 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
3347 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
3349 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3350 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
3352 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
3353 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
3355 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows)
3356 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
3361 verify_fieldrva_table (VerifyContext *ctx)
3363 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3364 guint32 data [MONO_FIELD_RVA_SIZE];
3367 for (i = 0; i < table->rows; ++i) {
3368 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
3370 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
3371 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
3373 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3374 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
3378 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 14) | (1 << 15))
3380 verify_assembly_table (VerifyContext *ctx)
3382 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3383 guint32 data [MONO_ASSEMBLY_SIZE], hash;
3386 if (table->rows > 1)
3387 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
3389 for (i = 0; i < table->rows; ++i) {
3390 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
3392 hash = data [MONO_ASSEMBLY_HASH_ALG];
3393 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
3394 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
3396 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
3397 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3399 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
3400 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3402 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3403 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3405 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3406 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3410 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
3412 verify_assemblyref_table (VerifyContext *ctx)
3414 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3415 guint32 data [MONO_ASSEMBLYREF_SIZE];
3418 for (i = 0; i < table->rows; ++i) {
3419 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3421 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3422 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3424 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3425 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3427 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3428 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3430 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3431 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3433 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3434 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3438 #define INVALID_FILE_FLAGS_BITS ~(1)
3440 verify_file_table (VerifyContext *ctx)
3442 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3443 guint32 data [MONO_FILE_SIZE];
3446 for (i = 0; i < table->rows; ++i) {
3447 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3449 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3450 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3452 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3453 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3455 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3456 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3460 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3462 verify_exportedtype_table (VerifyContext *ctx)
3464 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3465 guint32 data [MONO_EXP_TYPE_SIZE];
3468 for (i = 0; i < table->rows; ++i) {
3469 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3471 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3472 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3474 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3475 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3477 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3478 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3480 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3481 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3483 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3484 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3486 /*nested type can't have a namespace*/
3487 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3488 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3492 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3494 verify_manifest_resource_table (VerifyContext *ctx)
3496 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
3497 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3498 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3499 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3502 resources_size = ch->ch_resources.size;
3504 for (i = 0; i < table->rows; ++i) {
3505 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3507 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3508 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3510 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3511 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3513 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3514 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3516 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3517 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3519 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3520 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3522 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3523 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])));
3525 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3526 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3528 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3529 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3534 verify_nested_class_table (VerifyContext *ctx)
3536 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3537 guint32 data [MONO_NESTED_CLASS_SIZE];
3540 for (i = 0; i < table->rows; ++i) {
3541 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3543 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3544 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3545 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3546 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3547 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3548 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3552 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3554 verify_generic_param_table (VerifyContext *ctx)
3556 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3557 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3558 int i, param_number = 0;
3560 for (i = 0; i < table->rows; ++i) {
3561 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3563 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3564 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3566 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3567 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3569 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3570 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3572 token = data [MONO_GENERICPARAM_OWNER];
3574 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3575 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3577 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3578 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3580 if (token != last_token) {
3585 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3586 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));
3593 verify_method_spec_table (VerifyContext *ctx)
3595 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3596 guint32 data [MONO_METHODSPEC_SIZE];
3599 for (i = 0; i < table->rows; ++i) {
3600 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3602 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3603 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3605 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3606 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3608 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3609 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3614 verify_method_spec_table_full (VerifyContext *ctx)
3616 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3617 guint32 data [MONO_METHODSPEC_SIZE];
3620 for (i = 0; i < table->rows; ++i) {
3621 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3623 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3624 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3629 verify_generic_param_constraint_table (VerifyContext *ctx)
3631 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3632 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3634 guint32 last_owner = 0, last_constraint = 0;
3636 for (i = 0; i < table->rows; ++i) {
3637 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3639 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3640 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3642 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3643 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3645 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3646 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3648 if (last_owner > data [MONO_GENPARCONSTRAINT_GENERICPAR])
3649 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d is not properly sorted. Previous value of the owner column is 0x%08x current value is 0x%08x", i, last_owner, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3651 if (last_owner == data [MONO_GENPARCONSTRAINT_GENERICPAR]) {
3652 if (last_constraint == data [MONO_GENPARCONSTRAINT_CONSTRAINT])
3653 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has duplicate constraint 0x%08x", i, last_constraint));
3655 last_owner = data [MONO_GENPARCONSTRAINT_GENERICPAR];
3657 last_constraint = data [MONO_GENPARCONSTRAINT_CONSTRAINT];
3664 const char *name_space;
3665 guint32 resolution_scope;
3669 typedef_hash (gconstpointer _key)
3671 const TypeDefUniqueId *key = (const TypeDefUniqueId *)_key;
3672 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3676 typedef_equals (gconstpointer _a, gconstpointer _b)
3678 const TypeDefUniqueId *a = (const TypeDefUniqueId *)_a;
3679 const TypeDefUniqueId *b = (const TypeDefUniqueId *)_b;
3680 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3684 verify_typedef_table_global_constraints (VerifyContext *ctx)
3687 guint32 data [MONO_TYPEDEF_SIZE];
3688 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3689 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3690 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3691 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3693 for (i = 0; i < table->rows; ++i) {
3695 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3696 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3698 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3699 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3700 type->resolution_scope = 0;
3702 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3703 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3704 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3705 g_assert (res >= 0);
3707 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3708 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3711 if (g_hash_table_lookup (unique_types, type)) {
3712 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("TypeDef table row %d has duplicate for tuple (%s,%s,%x)", i, type->name, type->name_space, type->resolution_scope));
3713 g_hash_table_destroy (unique_types);
3717 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3720 g_hash_table_destroy (unique_types);
3724 verify_typeref_table_global_constraints (VerifyContext *ctx)
3727 guint32 data [MONO_TYPEREF_SIZE];
3728 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3729 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3731 for (i = 0; i < table->rows; ++i) {
3732 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3733 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3735 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3736 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3737 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3739 if (g_hash_table_lookup (unique_types, type)) {
3740 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("TypeRef table row %d has duplicate for tuple (%s,%s,%x)", i, type->name, type->name_space, type->resolution_scope));
3741 g_hash_table_destroy (unique_types);
3745 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3748 g_hash_table_destroy (unique_types);
3752 verify_tables_data_global_constraints (VerifyContext *ctx)
3754 verify_typedef_table_global_constraints (ctx);
3758 verify_tables_data_global_constraints_full (VerifyContext *ctx)
3760 verify_typeref_table (ctx);
3761 verify_typeref_table_global_constraints (ctx);
3765 verify_tables_data (VerifyContext *ctx)
3767 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3768 guint32 size = 0, tables_offset;
3771 for (i = 0; i < 0x2D; ++i) {
3772 MonoTableInfo *table = &ctx->image->tables [i];
3774 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3775 if (tmp_size < size) {
3783 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3785 tables_offset = ctx->image->tables_base - ctx->data;
3786 if (!bounds_check_offset (&tables_area, tables_offset, size))
3787 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)));
3789 verify_module_table (ctx);
3791 /*Obfuscators love to place broken stuff in the typeref table
3792 verify_typeref_table (ctx);
3794 verify_typedef_table (ctx);
3796 verify_field_table (ctx);
3798 verify_method_table (ctx);
3800 verify_param_table (ctx);
3802 verify_interfaceimpl_table (ctx);
3804 verify_memberref_table (ctx);
3806 verify_constant_table (ctx);
3808 verify_cattr_table (ctx);
3810 verify_field_marshal_table (ctx);
3812 verify_decl_security_table (ctx);
3814 verify_class_layout_table (ctx);
3816 verify_field_layout_table (ctx);
3818 verify_standalonesig_table (ctx);
3820 verify_eventmap_table (ctx);
3822 verify_event_table (ctx);
3824 verify_propertymap_table (ctx);
3826 verify_property_table (ctx);
3828 verify_methodimpl_table (ctx);
3830 verify_moduleref_table (ctx);
3832 verify_typespec_table (ctx);
3834 verify_implmap_table (ctx);
3836 verify_fieldrva_table (ctx);
3838 verify_assembly_table (ctx);
3840 verify_assemblyref_table (ctx);
3842 verify_file_table (ctx);
3844 verify_exportedtype_table (ctx);
3846 verify_manifest_resource_table (ctx);
3848 verify_nested_class_table (ctx);
3850 verify_generic_param_table (ctx);
3852 verify_method_spec_table (ctx);
3854 verify_generic_param_constraint_table (ctx);
3856 verify_tables_data_global_constraints (ctx);
3860 init_verify_context (VerifyContext *ctx, MonoImage *image, gboolean report_error)
3862 memset (ctx, 0, sizeof (VerifyContext));
3864 ctx->report_error = report_error;
3865 ctx->report_warning = FALSE; //export this setting in the API
3867 ctx->size = image->raw_data_len;
3868 ctx->data = image->raw_data;
3872 cleanup_context (VerifyContext *ctx, GSList **error_list)
3874 g_free (ctx->sections);
3876 *error_list = ctx->errors;
3878 mono_free_verify_list (ctx->errors);
3883 cleanup_context_checked (VerifyContext *ctx, MonoError *error)
3885 g_free (ctx->sections);
3887 MonoVerifyInfo *info = (MonoVerifyInfo *)ctx->errors->data;
3888 mono_error_set_bad_image (error, ctx->image, "%s", info->message);
3889 mono_free_verify_list (ctx->errors);
3895 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3899 if (!mono_verifier_is_enabled_for_image (image))
3902 init_verify_context (&ctx, image, error_list != NULL);
3903 ctx.stage = STAGE_PE;
3905 verify_msdos_header (&ctx);
3907 verify_pe_header (&ctx);
3909 verify_pe_optional_header (&ctx);
3911 load_section_table (&ctx);
3913 load_data_directories (&ctx);
3915 verify_import_table (&ctx);
3917 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3918 verify_resources_table (&ctx);
3921 return cleanup_context (&ctx, error_list);
3925 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3929 if (!mono_verifier_is_enabled_for_image (image))
3932 init_verify_context (&ctx, image, error_list != NULL);
3933 ctx.stage = STAGE_CLI;
3935 verify_cli_header (&ctx);
3937 verify_metadata_header (&ctx);
3939 verify_tables_schema (&ctx);
3942 return cleanup_context (&ctx, error_list);
3947 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3948 * Other verification checks are meant to be done lazily by the runtime. Those include:
3949 * blob items (signatures, method headers, custom attributes, etc)
3950 * type semantics related
3952 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3954 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3955 * operation still need more checking.
3958 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3962 if (!mono_verifier_is_enabled_for_image (image))
3965 init_verify_context (&ctx, image, error_list != NULL);
3966 ctx.stage = STAGE_TABLES;
3968 verify_tables_data (&ctx);
3970 return cleanup_context (&ctx, error_list);
3975 * Verifies all other constraints.
3978 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3982 if (!mono_verifier_is_enabled_for_image (image))
3985 init_verify_context (&ctx, image, error_list != NULL);
3986 ctx.stage = STAGE_TABLES;
3988 verify_typedef_table_full (&ctx);
3990 verify_field_table_full (&ctx);
3992 verify_method_table_full (&ctx);
3994 verify_memberref_table_full (&ctx);
3996 verify_cattr_table_full (&ctx);
3998 verify_field_marshal_table_full (&ctx);
4000 verify_decl_security_table_full (&ctx);
4002 verify_standalonesig_table_full (&ctx);
4004 verify_event_table_full (&ctx);
4006 verify_typespec_table_full (&ctx);
4008 verify_method_spec_table_full (&ctx);
4010 verify_tables_data_global_constraints_full (&ctx);
4013 return cleanup_context (&ctx, error_list);
4017 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4021 if (!mono_verifier_is_enabled_for_image (image))
4024 init_verify_context (&ctx, image, error_list != NULL);
4025 ctx.stage = STAGE_TABLES;
4027 is_valid_field_signature (&ctx, offset);
4028 return cleanup_context (&ctx, error_list);
4032 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4035 guint32 locals_token;
4037 if (!mono_verifier_is_enabled_for_image (image))
4040 init_verify_context (&ctx, image, error_list != NULL);
4041 ctx.stage = STAGE_TABLES;
4043 is_valid_method_header (&ctx, offset, &locals_token);
4045 guint32 sig_offset = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_STANDALONESIG], locals_token - 1, MONO_STAND_ALONE_SIGNATURE);
4046 is_valid_standalonesig_blob (&ctx, sig_offset);
4049 return cleanup_context (&ctx, error_list);
4053 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4057 mono_error_init (error);
4059 if (!mono_verifier_is_enabled_for_image (image))
4062 init_verify_context (&ctx, image, TRUE);
4063 ctx.stage = STAGE_TABLES;
4065 is_valid_method_signature (&ctx, offset);
4066 /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
4067 return cleanup_context_checked (&ctx, error);
4071 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4075 if (!mono_verifier_is_enabled_for_image (image))
4078 init_verify_context (&ctx, image, error_list != NULL);
4079 ctx.stage = STAGE_TABLES;
4081 is_valid_memberref_method_signature (&ctx, offset);
4082 return cleanup_context (&ctx, error_list);
4086 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4090 if (!mono_verifier_is_enabled_for_image (image))
4093 init_verify_context (&ctx, image, error_list != NULL);
4094 ctx.stage = STAGE_TABLES;
4096 is_valid_field_signature (&ctx, offset);
4097 return cleanup_context (&ctx, error_list);
4101 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4105 if (!mono_verifier_is_enabled_for_image (image))
4108 init_verify_context (&ctx, image, error_list != NULL);
4109 ctx.stage = STAGE_TABLES;
4111 is_valid_standalonesig_blob (&ctx, offset);
4112 return cleanup_context (&ctx, error_list);
4116 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4120 if (!mono_verifier_is_enabled_for_image (image))
4123 init_verify_context (&ctx, image, error_list != NULL);
4124 ctx.stage = STAGE_TABLES;
4127 is_valid_typespec_blob (&ctx, offset);
4128 return cleanup_context (&ctx, error_list);
4132 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4136 if (!mono_verifier_is_enabled_for_image (image))
4139 init_verify_context (&ctx, image, error_list != NULL);
4140 ctx.stage = STAGE_TABLES;
4142 is_valid_methodspec_blob (&ctx, offset);
4143 return cleanup_context (&ctx, error_list);
4147 verify_user_string (VerifyContext *ctx, guint32 offset)
4149 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
4150 guint32 entry_size, bytes;
4152 if (heap_us.size < offset)
4153 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
4155 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
4156 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
4158 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
4159 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
4161 entry_size += bytes;
4163 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
4164 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
4168 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4172 if (!mono_verifier_is_enabled_for_image (image))
4175 init_verify_context (&ctx, image, error_list != NULL);
4176 ctx.stage = STAGE_TABLES;
4178 verify_user_string (&ctx, offset);
4180 return cleanup_context (&ctx, error_list);
4184 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4188 if (!mono_verifier_is_enabled_for_image (image))
4191 init_verify_context (&ctx, image, error_list != NULL);
4192 ctx.stage = STAGE_TABLES;
4194 is_valid_cattr_blob (&ctx, offset);
4196 return cleanup_context (&ctx, error_list);
4200 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4204 if (!mono_verifier_is_enabled_for_image (image))
4207 init_verify_context (&ctx, image, error_list != NULL);
4208 ctx.stage = STAGE_TABLES;
4210 is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
4212 return cleanup_context (&ctx, error_list);
4216 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4218 MonoMethodSignature *original_sig;
4219 if (!mono_verifier_is_enabled_for_image (image))
4222 original_sig = mono_method_signature (method);
4223 if (original_sig->call_convention == MONO_CALL_VARARG) {
4224 if (original_sig->hasthis != signature->hasthis)
4226 if (original_sig->call_convention != signature->call_convention)
4228 if (original_sig->explicit_this != signature->explicit_this)
4230 if (original_sig->call_convention != signature->call_convention)
4232 if (original_sig->pinvoke != signature->pinvoke)
4234 if (original_sig->sentinelpos != signature->sentinelpos)
4236 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4244 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4246 MonoTableInfo *table = &image->tables [MONO_TABLE_TYPEREF];
4247 guint32 data [MONO_TYPEREF_SIZE];
4249 mono_error_init (error);
4251 if (!mono_verifier_is_enabled_for_image (image))
4254 if (row >= table->rows) {
4255 mono_error_set_bad_image (error, image, "Invalid typeref row %d - table has %d rows", row, table->rows);
4259 mono_metadata_decode_row (table, row, data, MONO_TYPEREF_SIZE);
4260 if (!is_valid_coded_index_with_image (image, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4261 mono_error_set_bad_image (error, image, "Invalid typeref row %d coded index 0x%08x", row, data [MONO_TYPEREF_SCOPE]);
4265 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4266 mono_error_set_bad_image (error, image, "The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", row);
4270 if (!data [MONO_TYPEREF_NAME] || !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAME], FALSE)) {
4271 mono_error_set_bad_image (error, image, "Invalid typeref row %d name token 0x%08x", row, data [MONO_TYPEREF_NAME]);
4275 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAMESPACE], FALSE)) {
4276 mono_error_set_bad_image (error, image, "Invalid typeref row %d namespace token 0x%08x", row, data [MONO_TYPEREF_NAMESPACE]);
4283 /*Perform additional verification including metadata ones*/
4285 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4287 MonoMethod *declaration, *body;
4288 MonoMethodSignature *body_sig, *decl_sig;
4289 MonoTableInfo *table = &image->tables [MONO_TABLE_METHODIMPL];
4290 guint32 data [MONO_METHODIMPL_SIZE];
4292 mono_error_init (error);
4294 if (!mono_verifier_is_enabled_for_image (image))
4297 if (row >= table->rows) {
4298 mono_error_set_bad_image (error, image, "Invalid methodimpl row %d - table has %d rows", row, table->rows);
4302 mono_metadata_decode_row (table, row, data, MONO_METHODIMPL_SIZE);
4304 body = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_BODY], NULL, error);
4308 declaration = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_DECLARATION], NULL, error);
4313 mono_class_setup_supertypes (class);
4314 if (!mono_class_has_parent (class, body->klass)) {
4315 mono_error_set_bad_image (error, image, "Invalid methodimpl body doesn't belong to parent for row %x", row);
4319 if (!(body_sig = mono_method_signature_checked (body, error))) {
4323 if (!(decl_sig = mono_method_signature_checked (declaration, error))) {
4327 if (!mono_verifier_is_signature_compatible (decl_sig, body_sig)) {
4328 mono_error_set_bad_image (error, image, "Invalid methodimpl body signature not compatible with declaration row %x", row);
4337 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4343 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
4349 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
4355 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4361 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4367 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4373 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4375 mono_error_init (error);
4380 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4386 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4392 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4398 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4404 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4410 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4416 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4423 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4425 mono_error_init (error);
4430 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4432 mono_error_init (error);
4437 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4443 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4448 #endif /* DISABLE_VERIFIER */