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>
31 #ifndef DISABLE_VERIFIER
33 TODO add fail fast mode
34 TODO add PE32+ support
35 TODO verify the entry point RVA and content.
36 TODO load_section_table and load_data_directories must take PE32+ into account
37 TODO add section relocation support
38 TODO verify the relocation table, since we really don't use, no need so far.
39 TODO do full PECOFF resources verification
40 TODO verify in the CLI header entry point and resources
41 TODO implement null token typeref validation
42 TODO verify table wide invariants for typedef (sorting and uniqueness)
43 TODO implement proper authenticode data directory validation
44 TODO verify properties that require multiple tables to be valid
45 FIXME use subtraction based bounds checking to avoid overflows
46 FIXME get rid of metadata_streams and other fields from VerifyContext
49 #ifdef MONO_VERIFIER_DEBUG
50 #define VERIFIER_DEBUG(code) do { code; } while (0)
52 #define VERIFIER_DEBUG(code)
55 #define INVALID_OFFSET ((guint32)-1)
56 #define INVALID_ADDRESS 0xffffffff
66 RESOURCE_TABLE_IDX = 2,
67 CERTIFICATE_TABLE_IDX = 4,
68 RELOCATION_TABLE_IDX = 5,
82 #define INVALID_TABLE (0xFF)
83 /*format: number of bits, number of tables, tables{n. tables} */
84 const static unsigned char coded_index_desc[] = {
85 #define TYPEDEF_OR_REF_DESC (0)
92 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
99 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
107 MONO_TABLE_INTERFACEIMPL,
108 MONO_TABLE_MEMBERREF,
110 MONO_TABLE_DECLSECURITY,
113 MONO_TABLE_STANDALONESIG,
114 MONO_TABLE_MODULEREF,
117 MONO_TABLE_ASSEMBLYREF,
119 MONO_TABLE_EXPORTEDTYPE,
120 MONO_TABLE_MANIFESTRESOURCE,
121 MONO_TABLE_GENERICPARAM,
123 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
129 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
136 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
145 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
151 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
155 MONO_TABLE_MEMBERREF,
157 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
163 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
167 MONO_TABLE_ASSEMBLYREF,
168 MONO_TABLE_EXPORTEDTYPE,
170 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
176 MONO_TABLE_MEMBERREF,
179 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
183 MONO_TABLE_MODULEREF,
184 MONO_TABLE_ASSEMBLYREF,
187 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
197 guint32 translated_offset;
209 guint32 rellocationsRVA;
210 guint16 numberOfRelocations;
225 gboolean report_error;
226 gboolean report_warning;
229 DataDirectory data_directories [16];
230 guint32 section_count;
231 SectionHeader *sections;
233 OffsetAndSize metadata_streams [5]; //offset from begin of the image
236 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
238 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
239 vinfo->info.status = __status; \
240 vinfo->info.message = ( __msg); \
241 vinfo->exception_type = (__exception); \
242 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
245 #define ADD_WARNING(__ctx, __msg) \
247 if ((__ctx)->report_warning) { \
248 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
249 (__ctx)->valid = 0; \
254 #define ADD_ERROR_NO_RETURN(__ctx, __msg) \
256 if ((__ctx)->report_error) \
257 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
258 (__ctx)->valid = 0; \
261 #define ADD_ERROR(__ctx, __msg) \
263 if ((__ctx)->report_error) \
264 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
265 (__ctx)->valid = 0; \
269 #define FAIL(__ctx, __msg) \
271 if ((__ctx)->report_error) \
272 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
273 (__ctx)->valid = 0; \
277 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
279 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
281 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
282 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
284 #if SIZEOF_VOID_P == 4
285 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
287 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
290 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
291 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
294 dword_align (const char *ptr)
296 #if SIZEOF_VOID_P == 8
297 return (const char *) (((guint64) (ptr + 3)) & ~3);
299 return (const char *) (((guint32) (ptr + 3)) & ~3);
304 add_from_mono_error (VerifyContext *ctx, MonoError *error)
306 if (mono_error_ok (error))
309 ADD_ERROR (ctx, g_strdup (mono_error_get_message (error)));
310 mono_error_cleanup (error);
314 pe_signature_offset (VerifyContext *ctx)
316 return read32 (ctx->data + 0x3c);
320 pe_header_offset (VerifyContext *ctx)
322 return read32 (ctx->data + 0x3c) + 4;
326 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
330 if (rva + size < rva) //overflow
333 if (ctx->stage > STAGE_PE) {
334 MonoCLIImageInfo *iinfo = ctx->image->image_info;
335 const int top = iinfo->cli_section_count;
336 MonoSectionTable *tables = iinfo->cli_section_tables;
339 for (i = 0; i < top; i++) {
340 guint32 base = tables->st_virtual_address;
341 guint32 end = base + tables->st_raw_data_size;
343 if (rva >= base && rva + size <= end)
346 /*if ((addr >= tables->st_virtual_address) &&
347 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
349 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
359 for (i = 0; i < ctx->section_count; ++i) {
360 guint32 base = ctx->sections [i].baseRVA;
361 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
362 if (rva >= base && rva + size <= end)
369 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
371 if (dir->translated_offset > offset)
373 if (dir->size < size)
375 return offset + size <= dir->translated_offset + dir->size;
379 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
381 if (off->offset > offset)
384 if (off->size < size)
387 return offset + size <= off->offset + off->size;
391 translate_rva (VerifyContext *ctx, guint32 rva)
395 if (ctx->stage > STAGE_PE)
396 return mono_cli_rva_image_map (ctx->image, rva);
401 for (i = 0; i < ctx->section_count; ++i) {
402 guint32 base = ctx->sections [i].baseRVA;
403 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
404 if (rva >= base && rva <= end) {
405 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
407 return res >= ctx->size ? INVALID_OFFSET : res;
411 return INVALID_OFFSET;
415 verify_msdos_header (VerifyContext *ctx)
419 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
420 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
421 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
422 lfanew = pe_signature_offset (ctx);
423 if (lfanew > ctx->size - 4)
424 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
428 verify_pe_header (VerifyContext *ctx)
430 guint32 offset = pe_signature_offset (ctx);
431 const char *pe_header = ctx->data + offset;
432 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
433 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
437 if (offset > ctx->size - 20)
438 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
439 if (read16 (pe_header) != 0x14c)
440 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
444 verify_pe_optional_header (VerifyContext *ctx)
446 guint32 offset = pe_header_offset (ctx);
447 guint32 header_size, file_alignment;
448 const char *pe_header = ctx->data + offset;
449 const char *pe_optional_header = pe_header + 20;
451 header_size = read16 (pe_header + 16);
454 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
455 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
457 if (offset > ctx->size - header_size || header_size > ctx->size)
458 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
460 if (read16 (pe_optional_header) == 0x10b) {
461 if (header_size != 224)
462 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
464 /* LAMESPEC MS plays around this value and ignore it during validation
465 if (read32 (pe_optional_header + 28) != 0x400000)
466 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
467 if (read32 (pe_optional_header + 32) != 0x2000)
468 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
469 file_alignment = read32 (pe_optional_header + 36);
470 if (file_alignment != 0x200 && file_alignment != 0x1000)
471 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
472 /* All the junk in the middle is irrelevant, specially for mono. */
473 if (read32 (pe_optional_header + 92) > 0x10)
474 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
476 if (read16 (pe_optional_header) == 0x20B)
477 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
479 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
484 load_section_table (VerifyContext *ctx)
487 SectionHeader *sections;
488 guint32 offset = pe_header_offset (ctx);
489 const char *ptr = ctx->data + offset;
490 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
492 offset += 244;/*FIXME, this constant is different under PE32+*/
495 if (num_sections * 40 > ctx->size - offset)
496 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
498 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
499 for (i = 0; i < num_sections; ++i) {
500 sections [i].size = read32 (ptr + 8);
501 sections [i].baseRVA = read32 (ptr + 12);
502 sections [i].baseOffset = read32 (ptr + 20);
503 sections [i].rellocationsRVA = read32 (ptr + 24);
504 sections [i].numberOfRelocations = read16 (ptr + 32);
508 ptr = ctx->data + offset; /*reset it to the beggining*/
509 for (i = 0; i < num_sections; ++i) {
510 guint32 raw_size, flags;
511 if (sections [i].baseOffset == 0)
512 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
513 if (sections [i].baseOffset >= ctx->size)
514 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
515 if (sections [i].size > ctx->size - sections [i].baseOffset)
516 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
518 raw_size = read32 (ptr + 16);
519 if (raw_size < sections [i].size)
520 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
522 if (raw_size > ctx->size - sections [i].baseOffset)
523 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
525 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
526 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
528 flags = read32 (ptr + 36);
529 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
530 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
531 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
538 is_valid_data_directory (int i)
540 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
541 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
545 load_data_directories (VerifyContext *ctx)
547 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
548 const char *ptr = ctx->data + offset;
551 for (i = 0; i < 16; ++i) {
552 guint32 rva = read32 (ptr);
553 guint32 size = read32 (ptr + 4);
555 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
556 if (i == CERTIFICATE_TABLE_IDX) {
560 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
561 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
563 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
564 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
566 ctx->data_directories [i].rva = rva;
567 ctx->data_directories [i].size = size;
568 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
574 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
576 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
579 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
582 guint32 hint_table_rva;
584 import_rva = translate_rva (ctx, import_rva);
585 g_assert (import_rva != INVALID_OFFSET);
587 hint_table_rva = read32 (ctx->data + import_rva);
588 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
589 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
591 hint_table_rva = translate_rva (ctx, hint_table_rva);
592 g_assert (hint_table_rva != INVALID_OFFSET);
593 ptr = ctx->data + hint_table_rva + 2;
595 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
596 char name[SIZE_OF_CORMAIN];
597 memcpy (name, ptr, SIZE_OF_CORMAIN);
598 name [SIZE_OF_CORMAIN - 1] = 0;
599 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
604 verify_import_table (VerifyContext *ctx)
606 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
607 guint32 offset = it.translated_offset;
608 const char *ptr = ctx->data + offset;
609 guint32 name_rva, ilt_rva, iat_rva;
611 g_assert (offset != INVALID_OFFSET);
614 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
616 ilt_rva = read32 (ptr);
617 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
618 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
620 name_rva = read32 (ptr + 12);
621 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
622 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
624 iat_rva = read32 (ptr + 16);
626 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
627 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
629 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
630 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));
634 name_rva = translate_rva (ctx, name_rva);
635 g_assert (name_rva != INVALID_OFFSET);
636 ptr = ctx->data + name_rva;
638 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
639 char name[SIZE_OF_MSCOREE];
640 memcpy (name, ptr, SIZE_OF_MSCOREE);
641 name [SIZE_OF_MSCOREE - 1] = 0;
642 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
647 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
652 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
656 verify_resources_table (VerifyContext *ctx)
658 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
660 guint16 named_entries, id_entries;
661 const char *ptr, *root, *end;
667 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));
669 offset = it.translated_offset;
670 root = ptr = ctx->data + offset;
671 end = root + it.size;
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 = 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 = bsearch (&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_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
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 = 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 : 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 = 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 : 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 << 8) | (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_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2663 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", 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)
2689 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", 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)
2928 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2931 guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2934 for (i = 0; i < table->rows; ++i) {
2935 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2937 if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2938 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2940 mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2941 switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2942 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2943 mtoken |= MONO_TOKEN_METHOD_DEF;
2945 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2946 mtoken |= MONO_TOKEN_MEMBER_REF;
2949 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2952 ctor = mono_get_method (ctx->image, mtoken, NULL);
2954 /*This can't fail since this is checked in is_valid_cattr_blob*/
2955 g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
2957 if (!is_valid_cattr_content (ctx, ctor, ptr, size))
2958 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2963 verify_field_marshal_table (VerifyContext *ctx)
2965 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2966 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2969 for (i = 0; i < table->rows; ++i) {
2970 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2972 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2973 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2975 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2976 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2978 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2979 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2981 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2982 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2987 verify_field_marshal_table_full (VerifyContext *ctx)
2989 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2990 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2993 for (i = 0; i < table->rows; ++i) {
2994 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2996 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2997 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
3002 verify_decl_security_table (VerifyContext *ctx)
3004 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3005 guint32 data [MONO_DECL_SECURITY_SIZE];
3008 for (i = 0; i < table->rows; ++i) {
3009 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3011 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3012 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
3014 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3015 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
3017 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
3018 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
3023 verify_decl_security_table_full (VerifyContext *ctx)
3025 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3026 guint32 data [MONO_DECL_SECURITY_SIZE];
3029 for (i = 0; i < table->rows; ++i) {
3030 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3032 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
3033 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
3038 verify_class_layout_table (VerifyContext *ctx)
3040 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
3041 guint32 data [MONO_CLASS_LAYOUT_SIZE];
3044 for (i = 0; i < table->rows; ++i) {
3045 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
3047 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3048 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
3050 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
3062 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3068 verify_field_layout_table (VerifyContext *ctx)
3070 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3071 guint32 data [MONO_FIELD_LAYOUT_SIZE];
3074 for (i = 0; i < table->rows; ++i) {
3075 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
3077 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3078 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
3083 verify_standalonesig_table (VerifyContext *ctx)
3085 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3086 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3089 for (i = 0; i < table->rows; ++i) {
3090 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3092 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
3093 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3098 verify_standalonesig_table_full (VerifyContext *ctx)
3100 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3101 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3104 for (i = 0; i < table->rows; ++i) {
3105 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3107 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
3108 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3113 verify_eventmap_table (VerifyContext *ctx)
3115 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3116 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3119 for (i = 0; i < table->rows; ++i) {
3120 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
3122 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3123 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
3125 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
3126 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
3128 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
3132 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3134 verify_event_table (VerifyContext *ctx)
3136 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3137 guint32 data [MONO_EVENT_SIZE];
3140 for (i = 0; i < table->rows; ++i) {
3141 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3143 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
3144 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
3146 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
3147 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
3149 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
3150 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
3155 verify_event_table_full (VerifyContext *ctx)
3157 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3158 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
3159 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
3160 gboolean found_add, found_remove;
3163 for (i = 0; i < table->rows; ++i) {
3164 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3166 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
3167 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
3169 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
3171 //first we move to the first row for this event
3173 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3177 //now move forward looking for AddOn and RemoveOn rows
3178 found_add = found_remove = FALSE;
3179 while (idx < sema_table->rows) {
3180 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
3181 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
3183 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3185 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3186 found_remove = TRUE;
3187 if (found_add && found_remove)
3193 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3195 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3200 verify_propertymap_table (VerifyContext *ctx)
3202 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3203 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3206 for (i = 0; i < table->rows; ++i) {
3207 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
3209 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3210 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
3212 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
3213 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
3215 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
3219 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3221 verify_property_table (VerifyContext *ctx)
3223 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3224 guint32 data [MONO_PROPERTY_SIZE];
3227 for (i = 0; i < table->rows; ++i) {
3228 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
3230 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
3231 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
3233 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
3234 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
3236 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
3237 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
3239 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
3240 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
3241 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
3247 verify_methodimpl_table (VerifyContext *ctx)
3249 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3250 guint32 data [MONO_METHODIMPL_SIZE];
3253 for (i = 0; i < table->rows; ++i) {
3254 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3256 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3257 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3259 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3260 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3262 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3263 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3265 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3266 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3268 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3269 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3274 verify_moduleref_table (VerifyContext *ctx)
3276 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3277 guint32 data [MONO_MODULEREF_SIZE];
3280 for (i = 0; i < table->rows; ++i) {
3281 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
3283 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
3284 ADD_ERROR (ctx, g_strdup_printf ("Invalid ModuleRef row %d name field %08x", i, data [MONO_MODULEREF_NAME]));
3289 verify_typespec_table (VerifyContext *ctx)
3291 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3292 guint32 data [MONO_TYPESPEC_SIZE];
3295 for (i = 0; i < table->rows; ++i) {
3296 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3298 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
3299 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3304 verify_typespec_table_full (VerifyContext *ctx)
3306 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3307 guint32 data [MONO_TYPESPEC_SIZE];
3310 for (i = 0; i < table->rows; ++i) {
3311 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3312 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
3313 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
3314 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3319 #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))
3321 verify_implmap_table (VerifyContext *ctx)
3323 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3324 guint32 data [MONO_IMPLMAP_SIZE], cconv;
3327 for (i = 0; i < table->rows; ++i) {
3328 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
3330 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
3331 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
3333 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
3334 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
3335 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
3337 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3338 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
3340 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
3341 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
3343 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3344 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
3346 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
3347 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
3349 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows)
3350 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
3355 verify_fieldrva_table (VerifyContext *ctx)
3357 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3358 guint32 data [MONO_FIELD_RVA_SIZE];
3361 for (i = 0; i < table->rows; ++i) {
3362 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
3364 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
3365 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
3367 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3368 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
3372 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 14) | (1 << 15))
3374 verify_assembly_table (VerifyContext *ctx)
3376 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3377 guint32 data [MONO_ASSEMBLY_SIZE], hash;
3380 if (table->rows > 1)
3381 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
3383 for (i = 0; i < table->rows; ++i) {
3384 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
3386 hash = data [MONO_ASSEMBLY_HASH_ALG];
3387 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
3388 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
3390 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
3391 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3393 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
3394 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3396 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3397 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3399 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3400 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3404 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
3406 verify_assemblyref_table (VerifyContext *ctx)
3408 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3409 guint32 data [MONO_ASSEMBLYREF_SIZE];
3412 for (i = 0; i < table->rows; ++i) {
3413 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3415 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3416 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3418 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3419 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3421 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3422 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3424 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3425 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3427 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3428 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3432 #define INVALID_FILE_FLAGS_BITS ~(1)
3434 verify_file_table (VerifyContext *ctx)
3436 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3437 guint32 data [MONO_FILE_SIZE];
3440 for (i = 0; i < table->rows; ++i) {
3441 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3443 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3444 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3446 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3447 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3449 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3450 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3454 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3456 verify_exportedtype_table (VerifyContext *ctx)
3458 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3459 guint32 data [MONO_EXP_TYPE_SIZE];
3462 for (i = 0; i < table->rows; ++i) {
3463 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3465 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3466 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3468 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3469 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3471 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3472 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3474 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3475 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3477 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3478 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3480 /*nested type can't have a namespace*/
3481 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3482 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3486 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3488 verify_manifest_resource_table (VerifyContext *ctx)
3490 MonoCLIImageInfo *iinfo = ctx->image->image_info;
3491 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3492 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3493 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3496 resources_size = ch->ch_resources.size;
3498 for (i = 0; i < table->rows; ++i) {
3499 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3501 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3502 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3504 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3505 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3507 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3508 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3510 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3511 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3513 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3514 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3516 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3517 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])));
3519 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3520 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3522 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3523 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3528 verify_nested_class_table (VerifyContext *ctx)
3530 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3531 guint32 data [MONO_NESTED_CLASS_SIZE];
3534 for (i = 0; i < table->rows; ++i) {
3535 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3537 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3538 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3539 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3540 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3541 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3542 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3546 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3548 verify_generic_param_table (VerifyContext *ctx)
3550 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3551 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3552 int i, param_number = 0;
3554 for (i = 0; i < table->rows; ++i) {
3555 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3557 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3558 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3560 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3561 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3563 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3564 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3566 token = data [MONO_GENERICPARAM_OWNER];
3568 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3569 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3571 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3572 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3574 if (token != last_token) {
3579 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3580 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));
3587 verify_method_spec_table (VerifyContext *ctx)
3589 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3590 guint32 data [MONO_METHODSPEC_SIZE];
3593 for (i = 0; i < table->rows; ++i) {
3594 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3596 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3597 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3599 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3600 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3602 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3603 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3608 verify_method_spec_table_full (VerifyContext *ctx)
3610 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3611 guint32 data [MONO_METHODSPEC_SIZE];
3614 for (i = 0; i < table->rows; ++i) {
3615 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3617 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3618 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3623 verify_generic_param_constraint_table (VerifyContext *ctx)
3625 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3626 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3629 for (i = 0; i < table->rows; ++i) {
3630 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3632 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3633 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3635 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3636 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3638 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3639 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3646 const char *name_space;
3647 guint32 resolution_scope;
3651 typedef_hash (gconstpointer _key)
3653 const TypeDefUniqueId *key = _key;
3654 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3658 typedef_equals (gconstpointer _a, gconstpointer _b)
3660 const TypeDefUniqueId *a = _a;
3661 const TypeDefUniqueId *b = _b;
3662 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3666 verify_typedef_table_global_constraints (VerifyContext *ctx)
3669 guint32 data [MONO_TYPEDEF_SIZE];
3670 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3671 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3672 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3673 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3675 for (i = 0; i < table->rows; ++i) {
3677 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3678 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3680 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3681 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3682 type->resolution_scope = 0;
3684 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3685 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3686 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3687 g_assert (res >= 0);
3689 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3690 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3693 if (g_hash_table_lookup (unique_types, type)) {
3694 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));
3695 g_hash_table_destroy (unique_types);
3699 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3702 g_hash_table_destroy (unique_types);
3706 verify_typeref_table_global_constraints (VerifyContext *ctx)
3709 guint32 data [MONO_TYPEREF_SIZE];
3710 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3711 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3713 for (i = 0; i < table->rows; ++i) {
3714 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3715 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3717 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3718 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3719 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3721 if (g_hash_table_lookup (unique_types, type)) {
3722 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));
3723 g_hash_table_destroy (unique_types);
3727 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3730 g_hash_table_destroy (unique_types);
3734 verify_tables_data_global_constraints (VerifyContext *ctx)
3736 verify_typedef_table_global_constraints (ctx);
3740 verify_tables_data_global_constraints_full (VerifyContext *ctx)
3742 verify_typeref_table (ctx);
3743 verify_typeref_table_global_constraints (ctx);
3747 verify_tables_data (VerifyContext *ctx)
3749 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3750 guint32 size = 0, tables_offset;
3753 for (i = 0; i < 0x2D; ++i) {
3754 MonoTableInfo *table = &ctx->image->tables [i];
3756 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3757 if (tmp_size < size) {
3765 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3767 tables_offset = ctx->image->tables_base - ctx->data;
3768 if (!bounds_check_offset (&tables_area, tables_offset, size))
3769 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)));
3771 verify_module_table (ctx);
3773 /*Obfuscators love to place broken stuff in the typeref table
3774 verify_typeref_table (ctx);
3776 verify_typedef_table (ctx);
3778 verify_field_table (ctx);
3780 verify_method_table (ctx);
3782 verify_param_table (ctx);
3784 verify_interfaceimpl_table (ctx);
3786 verify_memberref_table (ctx);
3788 verify_constant_table (ctx);
3790 verify_cattr_table (ctx);
3792 verify_field_marshal_table (ctx);
3794 verify_decl_security_table (ctx);
3796 verify_class_layout_table (ctx);
3798 verify_field_layout_table (ctx);
3800 verify_standalonesig_table (ctx);
3802 verify_eventmap_table (ctx);
3804 verify_event_table (ctx);
3806 verify_propertymap_table (ctx);
3808 verify_property_table (ctx);
3810 verify_methodimpl_table (ctx);
3812 verify_moduleref_table (ctx);
3814 verify_typespec_table (ctx);
3816 verify_implmap_table (ctx);
3818 verify_fieldrva_table (ctx);
3820 verify_assembly_table (ctx);
3822 verify_assemblyref_table (ctx);
3824 verify_file_table (ctx);
3826 verify_exportedtype_table (ctx);
3828 verify_manifest_resource_table (ctx);
3830 verify_nested_class_table (ctx);
3832 verify_generic_param_table (ctx);
3834 verify_method_spec_table (ctx);
3836 verify_generic_param_constraint_table (ctx);
3838 verify_tables_data_global_constraints (ctx);
3842 init_verify_context (VerifyContext *ctx, MonoImage *image, gboolean report_error)
3844 memset (ctx, 0, sizeof (VerifyContext));
3846 ctx->report_error = report_error;
3847 ctx->report_warning = FALSE; //export this setting in the API
3849 ctx->size = image->raw_data_len;
3850 ctx->data = image->raw_data;
3854 cleanup_context (VerifyContext *ctx, GSList **error_list)
3856 g_free (ctx->sections);
3858 *error_list = ctx->errors;
3860 mono_free_verify_list (ctx->errors);
3865 cleanup_context_checked (VerifyContext *ctx, MonoError *error)
3867 g_free (ctx->sections);
3869 MonoVerifyInfo *info = ctx->errors->data;
3870 mono_error_set_bad_image (error, ctx->image, "%s", info->message);
3871 mono_free_verify_list (ctx->errors);
3877 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3881 if (!mono_verifier_is_enabled_for_image (image))
3884 init_verify_context (&ctx, image, error_list != NULL);
3885 ctx.stage = STAGE_PE;
3887 verify_msdos_header (&ctx);
3889 verify_pe_header (&ctx);
3891 verify_pe_optional_header (&ctx);
3893 load_section_table (&ctx);
3895 load_data_directories (&ctx);
3897 verify_import_table (&ctx);
3899 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3900 verify_resources_table (&ctx);
3903 return cleanup_context (&ctx, error_list);
3907 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3911 if (!mono_verifier_is_enabled_for_image (image))
3914 init_verify_context (&ctx, image, error_list != NULL);
3915 ctx.stage = STAGE_CLI;
3917 verify_cli_header (&ctx);
3919 verify_metadata_header (&ctx);
3921 verify_tables_schema (&ctx);
3924 return cleanup_context (&ctx, error_list);
3929 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3930 * Other verification checks are meant to be done lazily by the runtime. Those include:
3931 * blob items (signatures, method headers, custom attributes, etc)
3932 * type semantics related
3934 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3936 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3937 * operation still need more checking.
3940 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3944 if (!mono_verifier_is_enabled_for_image (image))
3947 init_verify_context (&ctx, image, error_list != NULL);
3948 ctx.stage = STAGE_TABLES;
3950 verify_tables_data (&ctx);
3952 return cleanup_context (&ctx, error_list);
3957 * Verifies all other constraints.
3960 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3964 if (!mono_verifier_is_enabled_for_image (image))
3967 init_verify_context (&ctx, image, error_list != NULL);
3968 ctx.stage = STAGE_TABLES;
3970 verify_typedef_table_full (&ctx);
3972 verify_field_table_full (&ctx);
3974 verify_method_table_full (&ctx);
3976 verify_memberref_table_full (&ctx);
3978 verify_cattr_table_full (&ctx);
3980 verify_field_marshal_table_full (&ctx);
3982 verify_decl_security_table_full (&ctx);
3984 verify_standalonesig_table_full (&ctx);
3986 verify_event_table_full (&ctx);
3988 verify_typespec_table_full (&ctx);
3990 verify_method_spec_table_full (&ctx);
3992 verify_tables_data_global_constraints_full (&ctx);
3995 return cleanup_context (&ctx, error_list);
3999 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4003 if (!mono_verifier_is_enabled_for_image (image))
4006 init_verify_context (&ctx, image, error_list != NULL);
4007 ctx.stage = STAGE_TABLES;
4009 is_valid_field_signature (&ctx, offset);
4010 return cleanup_context (&ctx, error_list);
4014 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4017 guint32 locals_token;
4019 if (!mono_verifier_is_enabled_for_image (image))
4022 init_verify_context (&ctx, image, error_list != NULL);
4023 ctx.stage = STAGE_TABLES;
4025 is_valid_method_header (&ctx, offset, &locals_token);
4027 guint32 sig_offset = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_STANDALONESIG], locals_token - 1, MONO_STAND_ALONE_SIGNATURE);
4028 is_valid_standalonesig_blob (&ctx, sig_offset);
4031 return cleanup_context (&ctx, error_list);
4035 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4039 mono_error_init (error);
4041 if (!mono_verifier_is_enabled_for_image (image))
4044 init_verify_context (&ctx, image, TRUE);
4045 ctx.stage = STAGE_TABLES;
4047 is_valid_method_signature (&ctx, offset);
4048 /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
4049 return cleanup_context_checked (&ctx, error);
4053 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4057 if (!mono_verifier_is_enabled_for_image (image))
4060 init_verify_context (&ctx, image, error_list != NULL);
4061 ctx.stage = STAGE_TABLES;
4063 is_valid_memberref_method_signature (&ctx, offset);
4064 return cleanup_context (&ctx, error_list);
4068 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4072 if (!mono_verifier_is_enabled_for_image (image))
4075 init_verify_context (&ctx, image, error_list != NULL);
4076 ctx.stage = STAGE_TABLES;
4078 is_valid_field_signature (&ctx, offset);
4079 return cleanup_context (&ctx, error_list);
4083 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4087 if (!mono_verifier_is_enabled_for_image (image))
4090 init_verify_context (&ctx, image, error_list != NULL);
4091 ctx.stage = STAGE_TABLES;
4093 is_valid_standalonesig_blob (&ctx, offset);
4094 return cleanup_context (&ctx, error_list);
4098 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4102 if (!mono_verifier_is_enabled_for_image (image))
4105 init_verify_context (&ctx, image, error_list != NULL);
4106 ctx.stage = STAGE_TABLES;
4109 is_valid_typespec_blob (&ctx, offset);
4110 return cleanup_context (&ctx, error_list);
4114 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4118 if (!mono_verifier_is_enabled_for_image (image))
4121 init_verify_context (&ctx, image, error_list != NULL);
4122 ctx.stage = STAGE_TABLES;
4124 is_valid_methodspec_blob (&ctx, offset);
4125 return cleanup_context (&ctx, error_list);
4129 verify_user_string (VerifyContext *ctx, guint32 offset)
4131 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
4132 guint32 entry_size, bytes;
4134 if (heap_us.size < offset)
4135 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
4137 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
4138 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
4140 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
4141 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
4143 entry_size += bytes;
4145 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
4146 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
4150 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4154 if (!mono_verifier_is_enabled_for_image (image))
4157 init_verify_context (&ctx, image, error_list != NULL);
4158 ctx.stage = STAGE_TABLES;
4160 verify_user_string (&ctx, offset);
4162 return cleanup_context (&ctx, error_list);
4166 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4170 if (!mono_verifier_is_enabled_for_image (image))
4173 init_verify_context (&ctx, image, error_list != NULL);
4174 ctx.stage = STAGE_TABLES;
4176 is_valid_cattr_blob (&ctx, offset);
4178 return cleanup_context (&ctx, error_list);
4182 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4186 if (!mono_verifier_is_enabled_for_image (image))
4189 init_verify_context (&ctx, image, error_list != NULL);
4190 ctx.stage = STAGE_TABLES;
4192 is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
4194 return cleanup_context (&ctx, error_list);
4198 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4200 MonoMethodSignature *original_sig;
4201 if (!mono_verifier_is_enabled_for_image (image))
4204 original_sig = mono_method_signature (method);
4205 if (original_sig->call_convention == MONO_CALL_VARARG) {
4206 if (original_sig->hasthis != signature->hasthis)
4208 if (original_sig->call_convention != signature->call_convention)
4210 if (original_sig->explicit_this != signature->explicit_this)
4212 if (original_sig->call_convention != signature->call_convention)
4214 if (original_sig->pinvoke != signature->pinvoke)
4216 if (original_sig->sentinelpos != signature->sentinelpos)
4218 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4226 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4228 MonoTableInfo *table = &image->tables [MONO_TABLE_TYPEREF];
4229 guint32 data [MONO_TYPEREF_SIZE];
4231 mono_error_init (error);
4233 if (!mono_verifier_is_enabled_for_image (image))
4236 if (row >= table->rows) {
4237 mono_error_set_bad_image (error, image, "Invalid typeref row %d - table has %d rows", row, table->rows);
4241 mono_metadata_decode_row (table, row, data, MONO_TYPEREF_SIZE);
4242 if (!is_valid_coded_index_with_image (image, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4243 mono_error_set_bad_image (error, image, "Invalid typeref row %d coded index 0x%08x", row, data [MONO_TYPEREF_SCOPE]);
4247 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4248 mono_error_set_bad_image (error, image, "The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", row);
4252 if (!data [MONO_TYPEREF_NAME] || !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAME], FALSE)) {
4253 mono_error_set_bad_image (error, image, "Invalid typeref row %d name token 0x%08x", row, data [MONO_TYPEREF_NAME]);
4257 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAMESPACE], FALSE)) {
4258 mono_error_set_bad_image (error, image, "Invalid typeref row %d namespace token 0x%08x", row, data [MONO_TYPEREF_NAMESPACE]);
4265 /*Perform additional verification including metadata ones*/
4267 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4269 MonoMethod *declaration, *body;
4270 MonoMethodSignature *body_sig, *decl_sig;
4271 MonoTableInfo *table = &image->tables [MONO_TABLE_METHODIMPL];
4272 guint32 data [MONO_METHODIMPL_SIZE];
4274 mono_error_init (error);
4276 if (!mono_verifier_is_enabled_for_image (image))
4279 if (row >= table->rows) {
4280 mono_error_set_bad_image (error, image, "Invalid methodimpl row %d - table has %d rows", row, table->rows);
4284 mono_metadata_decode_row (table, row, data, MONO_METHODIMPL_SIZE);
4286 body = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_BODY], NULL);
4287 if (!body || mono_loader_get_last_error ()) {
4288 mono_loader_clear_error ();
4289 mono_error_set_bad_image (error, image, "Invalid methodimpl body for row %x", row);
4293 declaration = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_DECLARATION], NULL);
4294 if (!declaration || mono_loader_get_last_error ()) {
4295 mono_loader_clear_error ();
4296 mono_error_set_bad_image (error, image, "Invalid methodimpl declaration for row %x", row);
4301 mono_class_setup_supertypes (class);
4302 if (!mono_class_has_parent (class, body->klass)) {
4303 mono_error_set_bad_image (error, image, "Invalid methodimpl body doesn't belong to parent for row %x", row);
4307 if (!(body_sig = mono_method_signature_checked (body, error))) {
4311 if (!(decl_sig = mono_method_signature_checked (declaration, error))) {
4315 if (!mono_verifier_is_signature_compatible (decl_sig, body_sig)) {
4316 mono_error_set_bad_image (error, image, "Invalid methodimpl body signature not compatible with declaration row %x", row);
4325 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4331 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
4337 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
4343 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4349 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4355 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4361 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4363 mono_error_init (error);
4368 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4374 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4380 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4386 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4392 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4398 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4404 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4411 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4413 mono_error_init (error);
4418 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4420 mono_error_init (error);
4425 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4431 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4436 #endif /* DISABLE_VERIFIER */