3 * Metadata verfication support
6 * Mono Project (http://www.mono-project.com)
8 * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11 #include <mono/metadata/object-internals.h>
12 #include <mono/metadata/verify.h>
13 #include <mono/metadata/verify-internals.h>
14 #include <mono/metadata/opcodes.h>
15 #include <mono/metadata/tabledefs.h>
16 #include <mono/metadata/reflection.h>
17 #include <mono/metadata/debug-helpers.h>
18 #include <mono/metadata/mono-endian.h>
19 #include <mono/metadata/metadata.h>
20 #include <mono/metadata/metadata-internals.h>
21 #include <mono/metadata/class-internals.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/security-manager.h>
24 #include <mono/metadata/security-core-clr.h>
25 #include <mono/metadata/cil-coff.h>
26 #include <mono/metadata/attrdefs.h>
27 #include <mono/utils/strenc.h>
28 #include <mono/utils/mono-error-internals.h>
29 #include <mono/utils/bsearch.h>
34 #ifndef DISABLE_VERIFIER
36 TODO add fail fast mode
37 TODO add PE32+ support
38 TODO verify the entry point RVA and content.
39 TODO load_section_table and load_data_directories must take PE32+ into account
40 TODO add section relocation support
41 TODO verify the relocation table, since we really don't use, no need so far.
42 TODO do full PECOFF resources verification
43 TODO verify in the CLI header entry point and resources
44 TODO implement null token typeref validation
45 TODO verify table wide invariants for typedef (sorting and uniqueness)
46 TODO implement proper authenticode data directory validation
47 TODO verify properties that require multiple tables to be valid
48 FIXME use subtraction based bounds checking to avoid overflows
49 FIXME get rid of metadata_streams and other fields from VerifyContext
52 #ifdef MONO_VERIFIER_DEBUG
53 #define VERIFIER_DEBUG(code) do { code; } while (0)
55 #define VERIFIER_DEBUG(code)
58 #define INVALID_OFFSET ((guint32)-1)
59 #define INVALID_ADDRESS 0xffffffff
69 RESOURCE_TABLE_IDX = 2,
70 CERTIFICATE_TABLE_IDX = 4,
71 RELOCATION_TABLE_IDX = 5,
85 #define INVALID_TABLE (0xFF)
86 /*format: number of bits, number of tables, tables{n. tables} */
87 const static unsigned char coded_index_desc[] = {
88 #define TYPEDEF_OR_REF_DESC (0)
95 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
102 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
110 MONO_TABLE_INTERFACEIMPL,
111 MONO_TABLE_MEMBERREF,
113 MONO_TABLE_DECLSECURITY,
116 MONO_TABLE_STANDALONESIG,
117 MONO_TABLE_MODULEREF,
120 MONO_TABLE_ASSEMBLYREF,
122 MONO_TABLE_EXPORTEDTYPE,
123 MONO_TABLE_MANIFESTRESOURCE,
124 MONO_TABLE_GENERICPARAM,
126 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
132 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
139 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
144 MONO_TABLE_MODULEREF,
148 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
154 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
158 MONO_TABLE_MEMBERREF,
160 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
166 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
170 MONO_TABLE_ASSEMBLYREF,
171 MONO_TABLE_EXPORTEDTYPE,
173 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
179 MONO_TABLE_MEMBERREF,
182 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
186 MONO_TABLE_MODULEREF,
187 MONO_TABLE_ASSEMBLYREF,
190 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
200 guint32 translated_offset;
212 guint32 rellocationsRVA;
213 guint16 numberOfRelocations;
228 gboolean report_error;
229 gboolean report_warning;
232 DataDirectory data_directories [16];
233 guint32 section_count;
234 SectionHeader *sections;
236 OffsetAndSize metadata_streams [5]; //offset from begin of the image
239 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
241 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
242 vinfo->info.status = __status; \
243 vinfo->info.message = ( __msg); \
244 vinfo->exception_type = (__exception); \
245 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
248 #define ADD_WARNING(__ctx, __msg) \
250 if ((__ctx)->report_warning) { \
251 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
252 (__ctx)->valid = 0; \
257 #define ADD_ERROR_NO_RETURN(__ctx, __msg) \
259 if ((__ctx)->report_error) \
260 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
261 (__ctx)->valid = 0; \
264 #define ADD_ERROR(__ctx, __msg) \
266 if ((__ctx)->report_error) \
267 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
268 (__ctx)->valid = 0; \
272 #define FAIL(__ctx, __msg) \
274 if ((__ctx)->report_error) \
275 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
276 (__ctx)->valid = 0; \
280 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
282 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
284 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
285 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
287 #if SIZEOF_VOID_P == 4
288 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
290 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
293 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
294 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
297 dword_align (const char *ptr)
299 #if SIZEOF_VOID_P == 8
300 return (const char *) (((guint64) (ptr + 3)) & ~3);
302 return (const char *) (((guint32) (ptr + 3)) & ~3);
307 add_from_mono_error (VerifyContext *ctx, MonoError *error)
309 if (mono_error_ok (error))
312 ADD_ERROR (ctx, g_strdup (mono_error_get_message (error)));
313 mono_error_cleanup (error);
317 pe_signature_offset (VerifyContext *ctx)
319 return read32 (ctx->data + 0x3c);
323 pe_header_offset (VerifyContext *ctx)
325 return read32 (ctx->data + 0x3c) + 4;
329 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
333 if (rva + size < rva) //overflow
336 if (ctx->stage > STAGE_PE) {
337 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
338 const int top = iinfo->cli_section_count;
339 MonoSectionTable *tables = iinfo->cli_section_tables;
342 for (i = 0; i < top; i++) {
343 guint32 base = tables->st_virtual_address;
344 guint32 end = base + tables->st_raw_data_size;
346 if (rva >= base && rva + size <= end)
349 /*if ((addr >= tables->st_virtual_address) &&
350 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
352 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
362 for (i = 0; i < ctx->section_count; ++i) {
363 guint32 base = ctx->sections [i].baseRVA;
364 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
365 if (rva >= base && rva + size <= end)
372 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
374 if (dir->translated_offset > offset)
376 if (dir->size < size)
378 return offset + size <= dir->translated_offset + dir->size;
382 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
384 if (off->offset > offset)
387 if (off->size < size)
390 return offset + size <= off->offset + off->size;
394 translate_rva (VerifyContext *ctx, guint32 rva)
398 if (ctx->stage > STAGE_PE)
399 return mono_cli_rva_image_map (ctx->image, rva);
404 for (i = 0; i < ctx->section_count; ++i) {
405 guint32 base = ctx->sections [i].baseRVA;
406 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
407 if (rva >= base && rva <= end) {
408 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
410 return res >= ctx->size ? INVALID_OFFSET : res;
414 return INVALID_OFFSET;
418 verify_msdos_header (VerifyContext *ctx)
422 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
423 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
424 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
425 lfanew = pe_signature_offset (ctx);
426 if (lfanew > ctx->size - 4)
427 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
431 verify_pe_header (VerifyContext *ctx)
433 guint32 offset = pe_signature_offset (ctx);
434 const char *pe_header = ctx->data + offset;
435 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
436 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
440 if (offset > ctx->size - 20)
441 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
442 if (read16 (pe_header) != 0x14c)
443 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
447 verify_pe_optional_header (VerifyContext *ctx)
449 guint32 offset = pe_header_offset (ctx);
450 guint32 header_size, file_alignment;
451 const char *pe_header = ctx->data + offset;
452 const char *pe_optional_header = pe_header + 20;
454 header_size = read16 (pe_header + 16);
457 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
458 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
460 if (offset > ctx->size - header_size || header_size > ctx->size)
461 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
463 if (read16 (pe_optional_header) == 0x10b) {
464 if (header_size != 224)
465 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
467 /* LAMESPEC MS plays around this value and ignore it during validation
468 if (read32 (pe_optional_header + 28) != 0x400000)
469 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
470 if (read32 (pe_optional_header + 32) != 0x2000)
471 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
472 file_alignment = read32 (pe_optional_header + 36);
473 if (file_alignment != 0x200 && file_alignment != 0x1000)
474 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
475 /* All the junk in the middle is irrelevant, specially for mono. */
476 if (read32 (pe_optional_header + 92) > 0x10)
477 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
479 if (read16 (pe_optional_header) == 0x20B)
480 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
482 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
487 load_section_table (VerifyContext *ctx)
490 SectionHeader *sections;
491 guint32 offset = pe_header_offset (ctx);
492 const char *ptr = ctx->data + offset;
493 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
495 offset += 244;/*FIXME, this constant is different under PE32+*/
498 if (num_sections * 40 > ctx->size - offset)
499 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
501 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
502 for (i = 0; i < num_sections; ++i) {
503 sections [i].size = read32 (ptr + 8);
504 sections [i].baseRVA = read32 (ptr + 12);
505 sections [i].baseOffset = read32 (ptr + 20);
506 sections [i].rellocationsRVA = read32 (ptr + 24);
507 sections [i].numberOfRelocations = read16 (ptr + 32);
511 ptr = ctx->data + offset; /*reset it to the beggining*/
512 for (i = 0; i < num_sections; ++i) {
513 guint32 raw_size, flags;
514 if (sections [i].baseOffset == 0)
515 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
516 if (sections [i].baseOffset >= ctx->size)
517 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
518 if (sections [i].size > ctx->size - sections [i].baseOffset)
519 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
521 raw_size = read32 (ptr + 16);
522 if (raw_size < sections [i].size)
523 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
525 if (raw_size > ctx->size - sections [i].baseOffset)
526 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
528 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
529 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
531 flags = read32 (ptr + 36);
532 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
533 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
534 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
541 is_valid_data_directory (int i)
543 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
544 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
548 load_data_directories (VerifyContext *ctx)
550 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
551 const char *ptr = ctx->data + offset;
554 for (i = 0; i < 16; ++i) {
555 guint32 rva = read32 (ptr);
556 guint32 size = read32 (ptr + 4);
558 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
559 if (i == CERTIFICATE_TABLE_IDX) {
563 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
564 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
566 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
567 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
569 ctx->data_directories [i].rva = rva;
570 ctx->data_directories [i].size = size;
571 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
577 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
579 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
582 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
585 guint32 hint_table_rva;
587 import_rva = translate_rva (ctx, import_rva);
588 g_assert (import_rva != INVALID_OFFSET);
590 hint_table_rva = read32 (ctx->data + import_rva);
591 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
592 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
594 hint_table_rva = translate_rva (ctx, hint_table_rva);
595 g_assert (hint_table_rva != INVALID_OFFSET);
596 ptr = ctx->data + hint_table_rva + 2;
598 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
599 char name[SIZE_OF_CORMAIN];
600 memcpy (name, ptr, SIZE_OF_CORMAIN);
601 name [SIZE_OF_CORMAIN - 1] = 0;
602 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
607 verify_import_table (VerifyContext *ctx)
609 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
610 guint32 offset = it.translated_offset;
611 const char *ptr = ctx->data + offset;
612 guint32 name_rva, ilt_rva, iat_rva;
614 g_assert (offset != INVALID_OFFSET);
617 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
619 ilt_rva = read32 (ptr);
620 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
621 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
623 name_rva = read32 (ptr + 12);
624 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
625 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
627 iat_rva = read32 (ptr + 16);
629 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
630 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
632 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
633 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));
637 name_rva = translate_rva (ctx, name_rva);
638 g_assert (name_rva != INVALID_OFFSET);
639 ptr = ctx->data + name_rva;
641 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
642 char name[SIZE_OF_MSCOREE];
643 memcpy (name, ptr, SIZE_OF_MSCOREE);
644 name [SIZE_OF_MSCOREE - 1] = 0;
645 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
650 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
655 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
659 verify_resources_table (VerifyContext *ctx)
661 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
663 guint16 named_entries, id_entries;
670 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));
672 offset = it.translated_offset;
673 ptr = ctx->data + offset;
675 g_assert (offset != INVALID_OFFSET);
677 named_entries = read16 (ptr + 12);
678 id_entries = read16 (ptr + 14);
680 if ((named_entries + id_entries) * 8 + 16 > it.size)
681 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));
683 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
684 if (named_entries || id_entries)
685 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
689 /*----------nothing from here on can use data_directory---*/
692 get_data_dir (VerifyContext *ctx, int idx)
694 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
695 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
699 res.rva = entry->rva;
700 res.size = entry->size;
701 res.translated_offset = translate_rva (ctx, res.rva);
706 verify_cli_header (VerifyContext *ctx)
708 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
714 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
717 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
719 offset = it.translated_offset;
720 ptr = ctx->data + offset;
722 g_assert (offset != INVALID_OFFSET);
724 if (read16 (ptr) != 72)
725 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
727 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
728 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
731 if (!read32 (ptr + 8) || !read32 (ptr + 12))
732 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
734 if ((read32 (ptr + 16) & ~0x0003000B) != 0)
735 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
738 for (i = 0; i < 6; ++i) {
739 guint32 rva = read32 (ptr);
740 guint32 size = read32 (ptr + 4);
742 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
743 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
748 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
753 pad4 (guint32 offset)
755 if (offset & 0x3) //pad to the next 4 byte boundary
756 offset = (offset & ~0x3) + 4;
761 verify_metadata_header (VerifyContext *ctx)
764 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
765 guint32 offset, section_count;
768 offset = it.translated_offset;
769 ptr = ctx->data + offset;
770 g_assert (offset != INVALID_OFFSET);
772 //build a directory entry for the metadata root
774 it.rva = read32 (ptr);
776 it.size = read32 (ptr);
777 it.translated_offset = offset = translate_rva (ctx, it.rva);
779 ptr = ctx->data + offset;
780 g_assert (offset != INVALID_OFFSET);
783 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
785 if (read32 (ptr) != 0x424A5342)
786 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
788 offset = pad4 (offset + 16 + read32 (ptr + 12));
790 if (!bounds_check_datadir (&it, offset, 4))
791 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));
793 ptr = ctx->data + offset; //move to streams header
795 section_count = read16 (ptr + 2);
796 if (section_count < 2)
797 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 2 streams (#~ and #GUID)"));
802 for (i = 0; i < section_count; ++i) {
803 guint32 stream_off, stream_size;
804 int string_size, stream_idx;
806 if (!bounds_check_datadir (&it, offset, 8))
807 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));
809 stream_off = it.translated_offset + read32 (ptr);
810 stream_size = read32 (ptr + 4);
812 if (!bounds_check_datadir (&it, stream_off, stream_size))
813 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
818 for (string_size = 0; string_size < 32; ++string_size) {
819 if (!bounds_check_datadir (&it, offset++, 1))
820 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
821 if (!ptr [string_size])
825 if (ptr [string_size])
826 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
828 if (!strncmp ("#Strings", ptr, 9))
829 stream_idx = STRINGS_STREAM;
830 else if (!strncmp ("#US", ptr, 4))
831 stream_idx = USER_STRINGS_STREAM;
832 else if (!strncmp ("#Blob", ptr, 6))
833 stream_idx = BLOB_STREAM;
834 else if (!strncmp ("#GUID", ptr, 6))
835 stream_idx = GUID_STREAM;
836 else if (!strncmp ("#~", ptr, 3))
837 stream_idx = TILDE_STREAM;
839 ADD_WARNING (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
840 offset = pad4 (offset);
841 ptr = ctx->data + offset;
845 if (ctx->metadata_streams [stream_idx].offset != 0)
846 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
848 ctx->metadata_streams [stream_idx].offset = stream_off;
849 ctx->metadata_streams [stream_idx].size = stream_size;
851 offset = pad4 (offset);
852 ptr = ctx->data + offset;
855 if (!ctx->metadata_streams [TILDE_STREAM].size)
856 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
857 if (!ctx->metadata_streams [GUID_STREAM].size)
858 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
862 verify_tables_schema (VerifyContext *ctx)
864 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
865 unsigned offset = tables_area.offset;
866 const char *ptr = ctx->data + offset;
867 guint64 valid_tables;
871 if (tables_area.size < 24)
872 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
874 if (ptr [4] != 2 && ptr [4] != 1)
875 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
877 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
879 if ((ptr [6] & ~0x7) != 0)
880 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]));
882 valid_tables = read64 (ptr + 8);
884 for (i = 0; i < 64; ++i) {
885 if (!(valid_tables & ((guint64)1 << i)))
888 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
889 Unused: 0x1E 0x1F 0x2D-0x3F
890 We don't care about the MS extensions.*/
891 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
892 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i));
893 if (i == 0x1E || i == 0x1F || i >= 0x2D)
894 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
898 if (tables_area.size < 24 + count * 4)
899 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));
902 for (i = 0; i < 64; ++i) {
903 if (valid_tables & ((guint64)1 << i)) {
904 guint32 row_count = read32 (ptr);
905 if (row_count > (1 << 24) - 1)
906 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
912 /*----------nothing from here on can use data_directory or metadata_streams ---*/
915 get_col_offset (VerifyContext *ctx, int table, int column)
917 guint32 bitfield = ctx->image->tables [table].size_bitfield;
921 offset += mono_metadata_table_size (bitfield, column);
927 get_col_size (VerifyContext *ctx, int table, int column)
929 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
933 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
936 res.offset = header->data - ctx->data;
937 res.size = header->size;
943 is_valid_string_full_with_image (MonoImage *image, guint32 offset, gboolean allow_empty)
945 guint32 heap_offset = (char*)image->heap_strings.data - image->raw_data;
946 guint32 heap_size = image->heap_strings.size;
949 const char *data = image->raw_data + heap_offset;
951 if (offset >= heap_size)
953 if (CHECK_ADDP_OVERFLOW_UN (data, offset))
956 if (!mono_utf8_validate_and_len_with_bounds (data + offset, heap_size - offset, &length, NULL))
958 return allow_empty || length > 0;
963 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
965 return is_valid_string_full_with_image (ctx->image, offset, allow_empty);
969 is_valid_string (VerifyContext *ctx, guint32 offset)
971 return is_valid_string_full (ctx, offset, TRUE);
975 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
977 return is_valid_string_full (ctx, offset, FALSE);
981 is_valid_guid (VerifyContext *ctx, guint32 offset)
983 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
984 return guids.size >= 8 && guids.size - 8 >= offset;
988 get_coded_index_token (int token_kind, guint32 coded_token)
990 guint32 bits = coded_index_desc [token_kind];
991 return coded_token >> bits;
995 get_coded_index_table (int kind, guint32 coded_token)
997 guint32 idx, bits = coded_index_desc [kind];
999 idx = coded_token & ((1 << bits) - 1);
1000 return coded_index_desc [kind + idx];
1004 make_coded_token (int kind, guint32 table, guint32 table_idx)
1006 guint32 bits = coded_index_desc [kind++];
1007 guint32 tables = coded_index_desc [kind++];
1009 for (i = 0; i < tables; ++i) {
1010 if (coded_index_desc [kind++] == table)
1011 return ((table_idx + 1) << bits) | i;
1013 g_assert_not_reached ();
1018 is_valid_coded_index_with_image (MonoImage *image, int token_kind, guint32 coded_token)
1020 guint32 bits = coded_index_desc [token_kind++];
1021 guint32 table_count = coded_index_desc [token_kind++];
1022 guint32 table = coded_token & ((1 << bits) - 1);
1023 guint32 token = coded_token >> bits;
1025 if (table >= table_count)
1028 /*token_kind points to the first table idx*/
1029 table = coded_index_desc [token_kind + table];
1031 if (table == INVALID_TABLE)
1033 return token <= image->tables [table].rows;
1037 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
1039 return is_valid_coded_index_with_image (ctx->image, token_kind, coded_token);
1046 MonoTableInfo *table;
1050 token_locator (const void *a, const void *b)
1052 RowLocator *loc = (RowLocator *)a;
1053 unsigned const char *row = (unsigned const char *)b;
1054 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1056 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1057 return (int)loc->token - (int)token;
1061 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1063 MonoTableInfo *tinfo = &ctx->image->tables [table];
1065 const char *res, *base;
1066 locator.token = coded_token;
1067 locator.col_offset = get_col_offset (ctx, table, column);
1068 locator.col_size = get_col_size (ctx, table, column);
1069 locator.table = tinfo;
1073 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) );
1074 res = (const char *)mono_binary_search (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1078 return (res - base) / tinfo->row_size;
1081 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1083 get_string_ptr (VerifyContext *ctx, guint offset)
1085 return ctx->image->heap_strings.data + offset;
1088 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1090 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1093 return strcmp (str, "");
1095 return strcmp (str, get_string_ptr (ctx, offset));
1099 mono_verifier_is_corlib (MonoImage *image)
1101 gboolean trusted_location = !mono_security_core_clr_enabled () ?
1102 TRUE : mono_security_core_clr_is_platform_image (image);
1104 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1108 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1110 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1114 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1117 const unsigned char *ptr = (const unsigned char *)_ptr;
1125 if ((b & 0x80) == 0) {
1128 } else if ((b & 0x40) == 0) {
1132 *value = ((b & 0x3f) << 8 | ptr [1]);
1137 *value = ((b & 0x1f) << 24) |
1147 decode_signature_header (VerifyContext *ctx, guint32 offset, guint32 *size, const char **first_byte)
1149 MonoStreamHeader blob = ctx->image->heap_blob;
1150 guint32 value, enc_size;
1152 if (offset >= blob.size)
1155 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1158 if (CHECK_ADD4_OVERFLOW_UN (offset, enc_size))
1163 if (ADD_IS_GREATER_OR_OVF (offset, value, blob.size))
1167 *first_byte = blob.data + offset;
1172 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1174 const char *ptr = *_ptr;
1175 if (ptr + size > limit)
1179 *dest = *((guint8*)ptr);
1183 *dest = read16 (ptr);
1187 *dest = read32 (ptr);
1196 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1199 const char *ptr = *_ptr;
1200 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1205 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1206 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1207 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1208 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1211 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1214 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1217 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1219 const char *ptr = *_ptr;
1224 if (!safe_read8 (type, ptr, end))
1225 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1227 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1232 if (!safe_read_cint (token, ptr, end))
1233 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1235 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1236 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1244 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1246 const char *ptr = *_ptr;
1248 unsigned size, num, i;
1250 if (!safe_read8 (val, ptr, end))
1251 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1254 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1256 if (!safe_read_cint (size, ptr, end))
1257 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1259 for (i = 0; i < size; ++i) {
1260 if (!safe_read_cint (num, ptr, end))
1261 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1264 if (!safe_read_cint (size, ptr, end))
1265 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1267 for (i = 0; i < size; ++i) {
1268 if (!safe_read_cint (num, ptr, end))
1269 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1277 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1279 const char *ptr = *_ptr;
1281 unsigned count, token, i;
1283 if (!safe_read8 (type, ptr, end))
1284 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1286 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1287 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1289 if (!safe_read_cint (token, ptr, end))
1290 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1292 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1293 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1296 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1297 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1298 FAIL (ctx, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx->token));
1301 if (!safe_read_cint (count, ptr, end))
1302 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1305 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1307 for (i = 0; i < count; ++i) {
1308 if (!parse_custom_mods (ctx, &ptr, end))
1309 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1311 if (!parse_type (ctx, &ptr, end))
1312 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1319 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1321 const char *ptr = *_ptr;
1325 if (!safe_read8 (type, ptr, end))
1326 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1328 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1329 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1330 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1331 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1332 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1336 if (!parse_custom_mods (ctx, &ptr, end))
1337 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1339 if (!safe_read8 (type, ptr, end))
1340 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1342 if (type != MONO_TYPE_VOID) {
1344 if (!parse_type (ctx, &ptr, end))
1345 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1349 case MONO_TYPE_VALUETYPE:
1350 case MONO_TYPE_CLASS:
1351 if (!safe_read_cint (token, ptr, end))
1352 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1354 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1355 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1357 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1358 FAIL (ctx, g_strdup_printf ("Type: zero TypeDefOrRef token %x", token));
1360 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1361 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1362 FAIL (ctx, g_strdup_printf ("Type: Recursive type specification (%x). A type signature can't reference itself", ctx->token));
1367 case MONO_TYPE_MVAR:
1368 if (!safe_read_cint (token, ptr, end))
1369 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1372 case MONO_TYPE_ARRAY:
1373 if (!parse_type (ctx, &ptr, end))
1374 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1375 if (!parse_array_shape (ctx, &ptr, end))
1376 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1379 case MONO_TYPE_GENERICINST:
1380 if (!parse_generic_inst (ctx, &ptr, end))
1381 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1384 case MONO_TYPE_FNPTR:
1385 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1386 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1389 case MONO_TYPE_SZARRAY:
1390 if (!parse_custom_mods (ctx, &ptr, end))
1391 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1392 if (!parse_type (ctx, &ptr, end))
1393 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1401 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1406 if (!parse_custom_mods (ctx, _ptr, end))
1410 if (!safe_read8 (type, ptr, end))
1411 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1413 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1418 //it's a byref, update the cursor ptr
1419 if (type == MONO_TYPE_BYREF)
1422 return parse_type (ctx, _ptr, end);
1426 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1431 if (!parse_custom_mods (ctx, _ptr, end))
1435 if (!safe_read8 (type, ptr, end))
1436 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1438 if (type == MONO_TYPE_TYPEDBYREF) {
1443 //it's a byref, update the cursor ptr
1444 if (type == MONO_TYPE_BYREF) {
1446 if (!parse_custom_mods (ctx, _ptr, end))
1450 return parse_type (ctx, _ptr, end);
1454 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1457 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1458 const char *ptr = *_ptr;
1459 gboolean saw_sentinel = FALSE;
1461 if (!safe_read8 (cconv, ptr, end))
1462 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1465 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1467 if (allow_unmanaged) {
1468 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1469 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1470 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1471 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1473 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1474 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1476 if ((cconv & 0x10) && gparam_count == 0)
1477 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1479 if (allow_unmanaged && (cconv & 0x10))
1480 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1482 if (!safe_read_cint (param_count, ptr, end))
1483 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1485 if (!parse_return_type (ctx, &ptr, end))
1486 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1488 for (i = 0; i < param_count; ++i) {
1489 if (allow_sentinel) {
1490 if (!safe_read8 (type, ptr, end))
1491 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1493 if (type == MONO_TYPE_SENTINEL) {
1494 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1495 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1498 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1500 saw_sentinel = TRUE;
1506 if (!parse_param (ctx, &ptr, end))
1507 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1515 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1518 unsigned param_count = 0, i;
1519 const char *ptr = *_ptr;
1521 if (!safe_read8 (sig, ptr, end))
1522 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1524 if (sig != 0x08 && sig != 0x28)
1525 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1527 if (!safe_read_cint (param_count, ptr, end))
1528 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1530 if (!parse_custom_mods (ctx, &ptr, end))
1533 if (!parse_type (ctx, &ptr, end))
1534 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1536 for (i = 0; i < param_count; ++i) {
1537 if (!parse_custom_mods (ctx, &ptr, end))
1538 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1539 if (!parse_type (ctx, &ptr, end))
1540 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1548 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1550 const char *ptr = *_ptr;
1551 unsigned signature = 0;
1553 if (!safe_read8 (signature, ptr, end))
1554 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1556 if (signature != 0x06)
1557 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1559 if (!parse_custom_mods (ctx, &ptr, end))
1562 if (safe_read8 (signature, ptr, end)) {
1563 if (signature != MONO_TYPE_BYREF)
1568 return parse_type (ctx, _ptr, end);
1572 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1575 unsigned locals_count = 0, i;
1576 const char *ptr = *_ptr;
1578 if (!safe_read8 (sig, ptr, end))
1579 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1582 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1584 if (!safe_read_cint (locals_count, ptr, end))
1585 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1587 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1588 if (locals_count == 0)
1589 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1592 for (i = 0; i < locals_count; ++i) {
1593 if (!safe_read8 (sig, ptr, end))
1594 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1596 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1597 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1598 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1599 if (!safe_read8 (sig, ptr, end))
1600 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1603 if (sig == MONO_TYPE_BYREF) {
1604 if (!safe_read8 (sig, ptr, end))
1605 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1606 if (sig == MONO_TYPE_TYPEDBYREF)
1607 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1610 if (sig == MONO_TYPE_TYPEDBYREF)
1615 if (!parse_type (ctx, &ptr, end))
1616 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1624 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1627 unsigned signature = 0;
1628 const char *ptr = NULL, *end;
1630 if (!decode_signature_header (ctx, offset, &size, &ptr))
1631 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1634 if (!safe_read8 (signature, ptr, end))
1635 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1638 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1641 return parse_field (ctx, &ptr, end);
1645 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1648 const char *ptr = NULL, *end;
1650 if (!decode_signature_header (ctx, offset, &size, &ptr))
1651 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1654 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1658 is_valid_memberref_method_signature (VerifyContext *ctx, guint32 offset)
1661 const char *ptr = NULL, *end;
1663 if (!decode_signature_header (ctx, offset, &size, &ptr))
1664 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1667 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1672 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1675 unsigned signature = 0;
1676 const char *ptr = NULL, *end;
1678 if (!decode_signature_header (ctx, offset, &size, &ptr))
1679 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1682 if (!safe_read8 (signature, ptr, end))
1683 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1686 if (signature == 0x06)
1687 return parse_field (ctx, &ptr, end);
1689 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1693 is_valid_cattr_blob (VerifyContext *ctx, guint32 offset)
1696 unsigned prolog = 0;
1697 const char *ptr = NULL, *end;
1702 if (!decode_signature_header (ctx, offset, &size, &ptr))
1703 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1706 if (!safe_read16 (prolog, ptr, end))
1707 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1710 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1716 is_valid_cattr_type (MonoType *type)
1720 if (type->type == MONO_TYPE_OBJECT || (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_STRING))
1723 if (type->type == MONO_TYPE_VALUETYPE) {
1724 klass = mono_class_from_mono_type (type);
1725 return klass && klass->enumtype;
1728 if (type->type == MONO_TYPE_CLASS)
1729 return mono_class_from_mono_type (type) == mono_defaults.systemtype_class;
1735 is_valid_ser_string_full (VerifyContext *ctx, const char **str_start, guint32 *str_len, const char **_ptr, const char *end)
1738 const char *ptr = *_ptr;
1744 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1747 if (*ptr == (char)0xFF) {
1752 if (!safe_read_cint (size, ptr, end))
1753 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1755 if (ADDP_IS_GREATER_OR_OVF (ptr, size, end))
1756 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string"));
1766 is_valid_ser_string (VerifyContext *ctx, const char **_ptr, const char *end)
1768 const char *dummy_str;
1770 return is_valid_ser_string_full (ctx, &dummy_str, &dummy_int, _ptr, end);
1774 get_enum_by_encoded_name (VerifyContext *ctx, const char **_ptr, const char *end)
1778 const char *str_start = NULL;
1779 const char *ptr = *_ptr;
1781 guint32 str_len = 0;
1783 if (!is_valid_ser_string_full (ctx, &str_start, &str_len, &ptr, end))
1786 /*NULL or empty string*/
1787 if (str_start == NULL || str_len == 0) {
1788 ADD_ERROR_NO_RETURN (ctx, g_strdup ("CustomAttribute: Null or empty enum name"));
1792 enum_name = (char *)g_memdup (str_start, str_len + 1);
1793 enum_name [str_len] = 0;
1794 type = mono_reflection_type_from_name (enum_name, ctx->image);
1796 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid enum class %s", enum_name));
1802 klass = mono_class_from_mono_type (type);
1803 if (!klass || !klass->enumtype) {
1804 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute:Class %s::%s is not an enum", klass->name_space, klass->name));
1813 is_valid_fixed_param (VerifyContext *ctx, MonoType *mono_type, const char **_ptr, const char *end)
1816 const char *ptr = *_ptr;
1818 guint32 element_count, i;
1821 klass = mono_type->data.klass;
1822 type = mono_type->type;
1826 case MONO_TYPE_BOOLEAN:
1833 case MONO_TYPE_CHAR:
1847 case MONO_TYPE_STRING:
1849 return is_valid_ser_string (ctx, _ptr, end);
1851 case MONO_TYPE_OBJECT: {
1852 unsigned sub_type = 0;
1853 if (!safe_read8 (sub_type, ptr, end))
1854 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array type"));
1856 if (sub_type >= MONO_TYPE_BOOLEAN && sub_type <= MONO_TYPE_STRING) {
1860 if (sub_type == MONO_TYPE_ENUM) {
1861 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1865 klass = klass->element_class;
1866 type = klass->byval_arg.type;
1869 if (sub_type == 0x50) { /*Type*/
1871 return is_valid_ser_string (ctx, _ptr, end);
1873 if (sub_type == MONO_TYPE_SZARRAY) {
1874 MonoType simple_type = {{0}};
1876 if (!safe_read8 (etype, ptr, end))
1877 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1879 if (etype == MONO_TYPE_ENUM) {
1880 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1883 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
1884 klass = mono_defaults.systemtype_class;
1885 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1886 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : (MonoTypeEnum)etype;
1887 klass = mono_class_from_mono_type (&simple_type);
1889 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1891 type = MONO_TYPE_SZARRAY;
1894 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type));
1897 case MONO_TYPE_CLASS:
1898 if (klass && klass->enumtype) {
1899 klass = klass->element_class;
1900 type = klass->byval_arg.type;
1904 if (klass != mono_defaults.systemtype_class)
1905 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1907 return is_valid_ser_string (ctx, _ptr, end);
1909 case MONO_TYPE_VALUETYPE:
1910 if (!klass || !klass->enumtype)
1911 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass->name_space, klass->name));
1913 klass = klass->element_class;
1914 type = klass->byval_arg.type;
1917 case MONO_TYPE_SZARRAY:
1918 mono_type = &klass->byval_arg;
1919 if (!is_valid_cattr_type (mono_type))
1920 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass->name_space, klass->name));
1921 if (!safe_read32 (element_count, ptr, end))
1922 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1923 if (element_count == 0xFFFFFFFFu) {
1927 for (i = 0; i < element_count; ++i) {
1928 if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
1934 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
1937 if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
1938 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
1939 *_ptr = ptr + elem_size;
1944 is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
1947 unsigned prolog = 0;
1949 MonoMethodSignature *sig;
1954 FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
1956 sig = mono_method_signature_checked (ctor, &error);
1957 if (!mono_error_ok (&error)) {
1958 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error)));
1959 mono_error_cleanup (&error);
1963 if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
1964 FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1968 if (!safe_read16 (prolog, ptr, end))
1969 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1972 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1974 args = sig->param_count;
1975 for (i = 0; i < args; ++i) {
1976 MonoType *arg_type = sig->params [i];
1977 if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
1981 if (!safe_read16 (num_named, ptr, end))
1982 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
1984 for (i = 0; i < num_named; ++i) {
1985 MonoType *type, simple_type = {{0}};
1988 if (!safe_read8 (kind, ptr, end))
1989 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
1990 if (kind != 0x53 && kind != 0x54)
1991 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
1992 if (!safe_read8 (kind, ptr, end))
1993 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
1995 if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
1996 simple_type.type = (MonoTypeEnum)kind;
1997 type = &simple_type;
1998 } else if (kind == MONO_TYPE_ENUM) {
1999 MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
2002 type = &klass->byval_arg;
2003 } else if (kind == 0x50) {
2004 type = &mono_defaults.systemtype_class->byval_arg;
2005 } else if (kind == 0x51) {
2006 type = &mono_defaults.object_class->byval_arg;
2007 } else if (kind == MONO_TYPE_SZARRAY) {
2010 if (!safe_read8 (etype, ptr, end))
2011 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
2013 if (etype == MONO_TYPE_ENUM) {
2014 klass = get_enum_by_encoded_name (ctx, &ptr, end);
2017 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
2018 klass = mono_defaults.systemtype_class;
2019 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
2020 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : (MonoTypeEnum)etype;
2021 klass = mono_class_from_mono_type (&simple_type);
2023 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
2025 type = &mono_array_class_get (klass, 1)->byval_arg;
2027 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
2030 if (!is_valid_ser_string (ctx, &ptr, end))
2033 if (!is_valid_fixed_param (ctx, type, &ptr, end))
2042 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
2044 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2045 //TODO do proper verification
2046 return blob.size >= 1 && blob.size - 1 >= offset;
2050 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
2052 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2053 //TODO do proper verification
2054 return blob.size >= 1 && blob.size - 1 >= offset;
2058 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
2061 unsigned signature = 0;
2062 const char *ptr = NULL, *end;
2064 if (!decode_signature_header (ctx, offset, &size, &ptr))
2065 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
2068 if (!safe_read8 (signature, ptr, end))
2069 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2072 if (signature == 0x07)
2073 return parse_locals_signature (ctx, &ptr, end);
2075 /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
2076 if (signature == 0x06)
2077 return parse_field (ctx, &ptr, end);
2079 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
2083 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
2086 const char *ptr = NULL, *end;
2088 if (!decode_signature_header (ctx, offset, &size, &ptr))
2089 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
2092 return parse_property_signature (ctx, &ptr, end);
2096 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
2099 const char *ptr = NULL, *end;
2102 if (!decode_signature_header (ctx, offset, &size, &ptr))
2103 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
2106 if (!parse_custom_mods (ctx, &ptr, end))
2109 if (!safe_read8 (type, ptr, end))
2110 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
2112 if (type == MONO_TYPE_BYREF) {
2113 if (!safe_read8 (type, ptr, end))
2114 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
2115 if (type == MONO_TYPE_TYPEDBYREF)
2116 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
2119 if (type == MONO_TYPE_TYPEDBYREF)
2123 return parse_type (ctx, &ptr, end);
2127 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
2130 const char *ptr = NULL, *end;
2132 unsigned count = 0, i;
2134 if (!decode_signature_header (ctx, offset, &size, &ptr))
2135 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
2138 if (!safe_read8 (type, ptr, end))
2139 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
2142 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
2144 if (!safe_read_cint (count, ptr, end))
2145 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
2148 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
2150 for (i = 0; i < count; ++i) {
2151 if (!parse_custom_mods (ctx, &ptr, end))
2153 if (!parse_type (ctx, &ptr, end))
2154 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
2160 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
2162 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2163 guint32 entry_size, bytes;
2165 if (blob.size < offset)
2168 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2171 if (entry_size < minsize)
2174 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
2176 entry_size += bytes;
2178 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
2182 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
2184 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2185 guint32 size, entry_size, bytes;
2187 if (blob.size < offset)
2188 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
2190 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2191 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
2193 if (type == MONO_TYPE_STRING) {
2194 //String is encoded as: compressed_int:len len *bytes
2197 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
2198 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
2204 case MONO_TYPE_BOOLEAN:
2209 case MONO_TYPE_CHAR:
2217 case MONO_TYPE_CLASS:
2227 g_assert_not_reached ();
2230 if (size != entry_size)
2231 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
2235 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
2236 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
2238 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
2239 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
2243 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
2244 //only 0x01, 0x40 and 0x80 are allowed
2245 #define SECTION_HEADER_INVALID_FLAGS 0x3E
2248 is_valid_method_header (VerifyContext *ctx, guint32 rva, guint32 *locals_token)
2250 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
2251 unsigned header = 0;
2252 unsigned fat_header = 0, size = 0, max_stack;
2253 const char *ptr = NULL, *end;
2257 if (offset == INVALID_ADDRESS)
2258 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
2260 ptr = ctx->data + offset;
2261 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
2263 if (!safe_read8 (header, ptr, end))
2264 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
2266 switch (header & 0x3) {
2269 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
2272 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
2273 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
2278 if (!safe_read16 (fat_header, ptr, end))
2279 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
2281 size = (fat_header >> 12) & 0xF;
2283 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
2285 if (!safe_read16 (max_stack, ptr, end))
2286 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
2288 if (!safe_read32 (code_size, ptr, end))
2289 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
2291 if (!safe_read32 (local_vars_tok, ptr, end))
2292 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
2294 if (local_vars_tok) {
2295 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
2296 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
2297 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
2298 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
2299 if (!(local_vars_tok & 0xFFFFFF))
2300 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature with zero index"));
2301 *locals_token = local_vars_tok & 0xFFFFFF;
2304 if (fat_header & FAT_HEADER_INVALID_FLAGS)
2305 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
2307 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
2308 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
2310 if (!(fat_header & 0x08))
2316 unsigned section_header = 0, section_size = 0;
2319 ptr = dword_align (ptr);
2320 if (!safe_read32 (section_header, ptr, end))
2321 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
2323 if (section_header & SECTION_HEADER_INVALID_FLAGS)
2324 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
2326 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
2327 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
2329 if (section_size < 4)
2330 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
2332 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
2333 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
2335 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
2336 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
2338 LAMEIMPL: MS emits section_size without accounting for header size.
2339 Mono does as the spec says. section_size is header + section
2340 MS's peverify happily accepts both.
2342 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
2343 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)));
2345 /* only verify the class token is verified as the rest is done by the IL verifier*/
2346 for (i = 0; i < clauses; ++i) {
2347 unsigned flags = *(unsigned char*)ptr;
2348 unsigned class_token = 0;
2349 ptr += (is_fat ? 20 : 8);
2350 if (!safe_read32 (class_token, ptr, end))
2351 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
2352 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
2353 guint table = mono_metadata_token_table (class_token);
2354 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
2355 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
2356 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
2357 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
2362 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
2369 verify_module_table (VerifyContext *ctx)
2371 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
2372 guint32 data [MONO_MODULE_SIZE];
2374 if (table->rows != 1)
2375 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
2377 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
2379 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
2380 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
2382 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
2383 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
2385 if (data [MONO_MODULE_ENC] != 0)
2386 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
2388 if (data [MONO_MODULE_ENCBASE] != 0)
2389 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
2393 verify_typeref_table (VerifyContext *ctx)
2395 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2399 for (i = 0; i < table->rows; ++i) {
2400 mono_verifier_verify_typeref_row (ctx->image, i, &error);
2401 add_from_mono_error (ctx, &error);
2405 /*bits 9,11,14,15,19,21,24-31 */
2406 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2408 verify_typedef_table (VerifyContext *ctx)
2410 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2411 guint32 data [MONO_TYPEDEF_SIZE];
2412 guint32 fieldlist = 1, methodlist = 1, visibility;
2415 if (table->rows == 0)
2416 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2418 for (i = 0; i < table->rows; ++i) {
2419 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2420 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2421 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x rejected bits: 0x%08x", i, data [MONO_TYPEDEF_FLAGS], data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS));
2423 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2424 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2426 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2427 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2429 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2430 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2432 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2433 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2435 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2436 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2438 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2439 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2441 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2442 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2444 if (data [MONO_TYPEDEF_EXTENDS] && !get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2445 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d zero coded extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2447 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2448 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2449 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2450 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2452 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2453 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2455 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2456 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2458 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2459 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));
2461 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2462 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2464 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2465 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2467 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2468 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));
2470 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2471 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2476 verify_typedef_table_full (VerifyContext *ctx)
2478 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2479 guint32 data [MONO_TYPEDEF_SIZE];
2482 if (table->rows == 0)
2483 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2485 for (i = 0; i < table->rows; ++i) {
2486 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2489 /*XXX it's ok if <module> extends object, or anything at all, actually. */
2490 /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
2491 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2496 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2497 if (data [MONO_TYPEDEF_EXTENDS])
2498 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2500 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2501 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2505 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2508 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2516 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2518 verify_field_table (VerifyContext *ctx)
2520 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2521 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2524 module_field_list = (guint32)-1;
2525 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2526 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2527 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2530 for (i = 0; i < table->rows; ++i) {
2531 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2532 flags = data [MONO_FIELD_FLAGS];
2534 if (flags & INVALID_FIELD_FLAG_BITS)
2535 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2537 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2538 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2540 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2541 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2543 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2544 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2546 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2547 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2549 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2550 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2551 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2553 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2554 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2555 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2557 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2558 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2559 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2561 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2562 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2563 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2565 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2566 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2568 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2569 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2571 //TODO verify contant flag
2573 if (i + 1 < module_field_list) {
2574 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2575 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2576 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2577 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2578 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2584 verify_field_table_full (VerifyContext *ctx)
2586 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2587 guint32 data [MONO_FIELD_SIZE];
2590 for (i = 0; i < table->rows; ++i) {
2591 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2593 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2594 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2598 /*bits 8,9,10,11,13,14,15*/
2599 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2601 verify_method_table (VerifyContext *ctx)
2603 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2604 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2605 guint32 paramlist = 1;
2606 gboolean is_ctor, is_cctor;
2610 module_method_list = (guint32)-1;
2611 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2612 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2613 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2616 for (i = 0; i < table->rows; ++i) {
2617 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2618 rva = data [MONO_METHOD_RVA];
2619 implflags = data [MONO_METHOD_IMPLFLAGS];
2620 flags = data [MONO_METHOD_FLAGS];
2621 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2622 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2625 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2626 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2629 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2631 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2632 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2634 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2635 is_ctor = !strcmp (".ctor", name);
2636 is_cctor = !strcmp (".cctor", name);
2638 if ((is_ctor || is_cctor) &&
2639 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2640 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2642 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2643 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2645 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2646 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2647 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2648 if (flags & METHOD_ATTRIBUTE_FINAL)
2649 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2650 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2651 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2654 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2655 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2657 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2658 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2660 //XXX no checks against cas stuff 10,11,12,13)
2662 //TODO check iface with .ctor (15,16)
2664 if (i + 1 < module_method_list) {
2665 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2666 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2667 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2668 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2669 if (access == METHOD_ATTRIBUTE_FAMILY || access == METHOD_ATTRIBUTE_FAM_AND_ASSEM || access == METHOD_ATTRIBUTE_FAM_OR_ASSEM)
2670 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public, Private or Assembly", i));
2673 //TODO check valuetype for synchronized
2675 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2676 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2678 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2679 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2680 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2681 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2682 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2685 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2686 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2687 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2689 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2690 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2692 //TODO check signature contents
2695 if ((flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) || (implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
2696 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is either Abstract, InternalCall or PinvokeImpl", i));
2697 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2698 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2700 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2701 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2704 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2706 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2707 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2708 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2710 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2711 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2713 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2714 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2716 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2717 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2719 if (data [MONO_METHOD_PARAMLIST] == 0)
2720 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2722 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2723 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));
2725 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2726 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2728 paramlist = data [MONO_METHOD_PARAMLIST];
2734 verify_method_table_full (VerifyContext *ctx)
2736 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2737 guint32 data [MONO_METHOD_SIZE], rva, locals_token;
2740 for (i = 0; i < table->rows; ++i) {
2741 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2742 rva = data [MONO_METHOD_RVA];
2744 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2745 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2747 if (rva && !is_valid_method_header (ctx, rva, &locals_token))
2748 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2753 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2755 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2756 guint32 row = *current_method;
2757 guint32 paramlist, tmp;
2760 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2761 while (row < table->rows) {
2762 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2763 if (tmp > paramlist) {
2764 *current_method = row;
2765 return tmp - paramlist;
2770 /*no more methods, all params apply to the last one*/
2771 *current_method = table->rows;
2776 #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))
2778 verify_param_table (VerifyContext *ctx)
2780 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2781 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2782 gboolean first_param = TRUE;
2785 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2786 if (table->rows > 0)
2787 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2791 remaining_params = get_next_param_count (ctx, ¤t_method);
2793 for (i = 0; i < table->rows; ++i) {
2794 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2795 flags = data [MONO_PARAM_FLAGS];
2797 if (flags & INVALID_PARAM_FLAGS_BITS)
2798 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2800 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2801 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2802 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2804 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2805 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2808 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)
2809 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2811 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2812 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2814 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2815 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2817 first_param = FALSE;
2818 sequence = data [MONO_PARAM_SEQUENCE];
2819 if (--remaining_params == 0) {
2820 remaining_params = get_next_param_count (ctx, ¤t_method);
2827 verify_interfaceimpl_table (VerifyContext *ctx)
2829 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2830 guint32 data [MONO_INTERFACEIMPL_SIZE];
2833 for (i = 0; i < table->rows; ++i) {
2834 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2835 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2836 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_INTERFACEIMPL_CLASS]));
2838 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2839 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2841 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2842 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2847 verify_memberref_table (VerifyContext *ctx)
2849 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2850 guint32 data [MONO_MEMBERREF_SIZE];
2853 for (i = 0; i < table->rows; ++i) {
2854 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2856 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2857 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2859 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2860 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2862 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2863 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2865 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2866 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2872 verify_memberref_table_full (VerifyContext *ctx)
2874 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2875 guint32 data [MONO_MEMBERREF_SIZE];
2878 for (i = 0; i < table->rows; ++i) {
2879 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2881 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2882 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2887 verify_constant_table (VerifyContext *ctx)
2889 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2890 guint32 data [MONO_CONSTANT_SIZE], type;
2893 for (i = 0; i < table->rows; ++i) {
2894 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2895 type = data [MONO_CONSTANT_TYPE];
2897 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2898 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2900 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2901 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2903 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2904 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2906 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2907 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2912 verify_cattr_table (VerifyContext *ctx)
2914 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2915 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2918 for (i = 0; i < table->rows; ++i) {
2919 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2921 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2922 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2924 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]))
2925 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Type field 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2927 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2928 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2933 verify_cattr_table_full (VerifyContext *ctx)
2936 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2939 guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2942 for (i = 0; i < table->rows; ++i) {
2943 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2945 if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2946 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2948 mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2949 switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2950 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2951 mtoken |= MONO_TOKEN_METHOD_DEF;
2953 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2954 mtoken |= MONO_TOKEN_MEMBER_REF;
2957 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2960 ctor = mono_get_method_checked (ctx->image, mtoken, NULL, NULL, &error);
2963 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Could not load ctor due to %s", i, mono_error_get_message (&error)));
2964 mono_error_cleanup (&error);
2967 /*This can't fail since this is checked in is_valid_cattr_blob*/
2968 g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
2970 if (!is_valid_cattr_content (ctx, ctor, ptr, size)) {
2971 char *ctor_name = mono_method_full_name (ctor, TRUE);
2972 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x ctor: %s", i, data [MONO_CUSTOM_ATTR_VALUE], ctor_name));
2979 verify_field_marshal_table (VerifyContext *ctx)
2981 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2982 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2985 for (i = 0; i < table->rows; ++i) {
2986 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2988 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2989 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2991 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2992 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2994 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2995 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2997 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2998 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
3003 verify_field_marshal_table_full (VerifyContext *ctx)
3005 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
3006 guint32 data [MONO_FIELD_MARSHAL_SIZE];
3009 for (i = 0; i < table->rows; ++i) {
3010 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
3012 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
3013 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
3018 verify_decl_security_table (VerifyContext *ctx)
3020 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3021 guint32 data [MONO_DECL_SECURITY_SIZE];
3024 for (i = 0; i < table->rows; ++i) {
3025 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3027 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3028 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
3030 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3031 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
3033 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
3034 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
3039 verify_decl_security_table_full (VerifyContext *ctx)
3041 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3042 guint32 data [MONO_DECL_SECURITY_SIZE];
3045 for (i = 0; i < table->rows; ++i) {
3046 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3048 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
3049 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
3054 verify_class_layout_table (VerifyContext *ctx)
3056 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
3057 guint32 data [MONO_CLASS_LAYOUT_SIZE];
3060 for (i = 0; i < table->rows; ++i) {
3061 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
3063 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3064 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
3066 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
3078 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3084 verify_field_layout_table (VerifyContext *ctx)
3086 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3087 guint32 data [MONO_FIELD_LAYOUT_SIZE];
3090 for (i = 0; i < table->rows; ++i) {
3091 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
3093 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3094 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
3099 verify_standalonesig_table (VerifyContext *ctx)
3101 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3102 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3105 for (i = 0; i < table->rows; ++i) {
3106 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3108 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
3109 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3114 verify_standalonesig_table_full (VerifyContext *ctx)
3116 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3117 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3120 for (i = 0; i < table->rows; ++i) {
3121 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3123 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
3124 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3129 verify_eventmap_table (VerifyContext *ctx)
3131 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3132 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3135 for (i = 0; i < table->rows; ++i) {
3136 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
3138 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3139 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
3141 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
3142 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
3144 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
3148 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3150 verify_event_table (VerifyContext *ctx)
3152 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3153 guint32 data [MONO_EVENT_SIZE];
3156 for (i = 0; i < table->rows; ++i) {
3157 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3159 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
3160 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
3162 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
3163 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
3165 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
3166 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
3171 verify_event_table_full (VerifyContext *ctx)
3173 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3174 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
3175 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
3176 gboolean found_add, found_remove;
3179 for (i = 0; i < table->rows; ++i) {
3180 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3182 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
3183 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
3185 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
3187 //first we move to the first row for this event
3189 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3193 //now move forward looking for AddOn and RemoveOn rows
3194 found_add = found_remove = FALSE;
3195 while (idx < sema_table->rows) {
3196 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
3197 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
3199 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3201 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3202 found_remove = TRUE;
3203 if (found_add && found_remove)
3209 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3211 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no RemoveOn associated method", i));
3216 verify_propertymap_table (VerifyContext *ctx)
3218 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3219 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3222 for (i = 0; i < table->rows; ++i) {
3223 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
3225 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3226 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
3228 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
3229 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
3231 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
3235 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3237 verify_property_table (VerifyContext *ctx)
3239 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3240 guint32 data [MONO_PROPERTY_SIZE];
3243 for (i = 0; i < table->rows; ++i) {
3244 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
3246 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
3247 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
3249 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
3250 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
3252 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
3253 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
3255 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
3256 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
3257 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
3263 verify_methodimpl_table (VerifyContext *ctx)
3265 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3266 guint32 data [MONO_METHODIMPL_SIZE];
3269 for (i = 0; i < table->rows; ++i) {
3270 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3272 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3273 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3275 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3276 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3278 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3279 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3281 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3282 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3284 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3285 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3290 verify_moduleref_table (VerifyContext *ctx)
3292 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3293 guint32 data [MONO_MODULEREF_SIZE];
3296 for (i = 0; i < table->rows; ++i) {
3297 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
3299 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
3300 ADD_ERROR (ctx, g_strdup_printf ("Invalid ModuleRef row %d name field %08x", i, data [MONO_MODULEREF_NAME]));
3305 verify_typespec_table (VerifyContext *ctx)
3307 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3308 guint32 data [MONO_TYPESPEC_SIZE];
3311 for (i = 0; i < table->rows; ++i) {
3312 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3314 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
3315 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3320 verify_typespec_table_full (VerifyContext *ctx)
3322 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3323 guint32 data [MONO_TYPESPEC_SIZE];
3326 for (i = 0; i < table->rows; ++i) {
3327 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3328 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
3329 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
3330 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3335 #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))
3337 verify_implmap_table (VerifyContext *ctx)
3339 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3340 guint32 data [MONO_IMPLMAP_SIZE], cconv;
3343 for (i = 0; i < table->rows; ++i) {
3344 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
3346 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
3347 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
3349 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
3350 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
3351 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
3353 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3354 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
3356 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
3357 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
3359 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3360 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
3362 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
3363 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
3365 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows)
3366 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
3371 verify_fieldrva_table (VerifyContext *ctx)
3373 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3374 guint32 data [MONO_FIELD_RVA_SIZE];
3377 for (i = 0; i < table->rows; ++i) {
3378 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
3380 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
3381 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
3383 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3384 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
3388 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 14) | (1 << 15))
3390 verify_assembly_table (VerifyContext *ctx)
3392 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3393 guint32 data [MONO_ASSEMBLY_SIZE], hash;
3396 if (table->rows > 1)
3397 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
3399 for (i = 0; i < table->rows; ++i) {
3400 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
3402 hash = data [MONO_ASSEMBLY_HASH_ALG];
3403 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
3404 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
3406 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
3407 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3409 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
3410 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3412 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3413 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3415 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3416 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3420 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
3422 verify_assemblyref_table (VerifyContext *ctx)
3424 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3425 guint32 data [MONO_ASSEMBLYREF_SIZE];
3428 for (i = 0; i < table->rows; ++i) {
3429 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3431 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3432 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3434 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3435 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3437 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3438 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3440 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3441 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3443 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3444 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3448 #define INVALID_FILE_FLAGS_BITS ~(1)
3450 verify_file_table (VerifyContext *ctx)
3452 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3453 guint32 data [MONO_FILE_SIZE];
3456 for (i = 0; i < table->rows; ++i) {
3457 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3459 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3460 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3462 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3463 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3465 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3466 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3470 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3472 verify_exportedtype_table (VerifyContext *ctx)
3474 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3475 guint32 data [MONO_EXP_TYPE_SIZE];
3478 for (i = 0; i < table->rows; ++i) {
3479 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3481 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3482 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3484 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3485 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3487 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3488 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3490 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3491 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3493 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3494 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3496 /*nested type can't have a namespace*/
3497 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3498 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3502 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3504 verify_manifest_resource_table (VerifyContext *ctx)
3506 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
3507 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3508 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3509 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3512 resources_size = ch->ch_resources.size;
3514 for (i = 0; i < table->rows; ++i) {
3515 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3517 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3518 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3520 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3521 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3523 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3524 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3526 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3527 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3529 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3530 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3532 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3533 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])));
3535 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3536 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3538 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3539 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3544 verify_nested_class_table (VerifyContext *ctx)
3546 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3547 guint32 data [MONO_NESTED_CLASS_SIZE];
3550 for (i = 0; i < table->rows; ++i) {
3551 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3553 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3554 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3555 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3556 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3557 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3558 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3562 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3564 verify_generic_param_table (VerifyContext *ctx)
3566 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3567 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3568 int i, param_number = 0;
3570 for (i = 0; i < table->rows; ++i) {
3571 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3573 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3574 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3576 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3577 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3579 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3580 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3582 token = data [MONO_GENERICPARAM_OWNER];
3584 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3585 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3587 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3588 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3590 if (token != last_token) {
3595 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3596 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));
3603 verify_method_spec_table (VerifyContext *ctx)
3605 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3606 guint32 data [MONO_METHODSPEC_SIZE];
3609 for (i = 0; i < table->rows; ++i) {
3610 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3612 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3613 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3615 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3616 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3618 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3619 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3624 verify_method_spec_table_full (VerifyContext *ctx)
3626 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3627 guint32 data [MONO_METHODSPEC_SIZE];
3630 for (i = 0; i < table->rows; ++i) {
3631 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3633 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3634 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3639 verify_generic_param_constraint_table (VerifyContext *ctx)
3641 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3642 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3644 guint32 last_owner = 0, last_constraint = 0;
3646 for (i = 0; i < table->rows; ++i) {
3647 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3649 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3650 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3652 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3653 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3655 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3656 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3658 if (last_owner > data [MONO_GENPARCONSTRAINT_GENERICPAR])
3659 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d is not properly sorted. Previous value of the owner column is 0x%08x current value is 0x%08x", i, last_owner, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3661 if (last_owner == data [MONO_GENPARCONSTRAINT_GENERICPAR]) {
3662 if (last_constraint == data [MONO_GENPARCONSTRAINT_CONSTRAINT])
3663 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has duplicate constraint 0x%08x", i, last_constraint));
3665 last_owner = data [MONO_GENPARCONSTRAINT_GENERICPAR];
3667 last_constraint = data [MONO_GENPARCONSTRAINT_CONSTRAINT];
3674 const char *name_space;
3675 guint32 resolution_scope;
3679 typedef_hash (gconstpointer _key)
3681 const TypeDefUniqueId *key = (const TypeDefUniqueId *)_key;
3682 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3686 typedef_equals (gconstpointer _a, gconstpointer _b)
3688 const TypeDefUniqueId *a = (const TypeDefUniqueId *)_a;
3689 const TypeDefUniqueId *b = (const TypeDefUniqueId *)_b;
3690 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3694 verify_typedef_table_global_constraints (VerifyContext *ctx)
3697 guint32 data [MONO_TYPEDEF_SIZE];
3698 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3699 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3700 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3701 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3703 for (i = 0; i < table->rows; ++i) {
3705 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3706 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3708 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3709 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3710 type->resolution_scope = 0;
3712 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3713 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3714 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3715 g_assert (res >= 0);
3717 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3718 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3721 if (g_hash_table_lookup (unique_types, type)) {
3722 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));
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_typeref_table_global_constraints (VerifyContext *ctx)
3737 guint32 data [MONO_TYPEREF_SIZE];
3738 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3739 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3741 for (i = 0; i < table->rows; ++i) {
3742 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3743 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3745 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3746 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3747 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3749 if (g_hash_table_lookup (unique_types, type)) {
3750 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));
3751 g_hash_table_destroy (unique_types);
3755 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3758 g_hash_table_destroy (unique_types);
3763 guint32 method_declaration;
3764 } MethodImplUniqueId;
3767 methodimpl_hash (gconstpointer _key)
3769 const MethodImplUniqueId *key = (const MethodImplUniqueId *)_key;
3770 return key->klass ^ key->method_declaration;
3774 methodimpl_equals (gconstpointer _a, gconstpointer _b)
3776 const MethodImplUniqueId *a = (const MethodImplUniqueId *)_a;
3777 const MethodImplUniqueId *b = (const MethodImplUniqueId *)_b;
3778 return a->klass == b->klass && a->method_declaration == b->method_declaration;
3782 verify_methodimpl_table_global_constraints (VerifyContext *ctx)
3785 guint32 data [MONO_METHODIMPL_SIZE];
3786 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3787 GHashTable *unique_impls = g_hash_table_new_full (&methodimpl_hash, &methodimpl_equals, g_free, NULL);
3789 for (i = 0; i < table->rows; ++i) {
3790 MethodImplUniqueId *impl = g_new (MethodImplUniqueId, 1);
3791 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3793 impl->klass = data [MONO_METHODIMPL_CLASS];
3794 impl->method_declaration = data [MONO_METHODIMPL_DECLARATION];
3796 if (g_hash_table_lookup (unique_impls, impl)) {
3797 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("MethodImpl table row %d has duplicate for tuple (0x%x, 0x%x)", impl->klass, impl->method_declaration));
3798 g_hash_table_destroy (unique_impls);
3802 g_hash_table_insert (unique_impls, impl, GUINT_TO_POINTER (1));
3805 g_hash_table_destroy (unique_impls);
3810 verify_tables_data_global_constraints (VerifyContext *ctx)
3812 verify_typedef_table_global_constraints (ctx);
3816 verify_tables_data_global_constraints_full (VerifyContext *ctx)
3818 verify_typeref_table (ctx);
3819 verify_typeref_table_global_constraints (ctx);
3820 verify_methodimpl_table_global_constraints (ctx);
3824 verify_tables_data (VerifyContext *ctx)
3826 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3827 guint32 size = 0, tables_offset;
3830 for (i = 0; i < 0x2D; ++i) {
3831 MonoTableInfo *table = &ctx->image->tables [i];
3833 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3834 if (tmp_size < size) {
3842 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3844 tables_offset = ctx->image->tables_base - ctx->data;
3845 if (!bounds_check_offset (&tables_area, tables_offset, size))
3846 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)));
3848 verify_module_table (ctx);
3850 /*Obfuscators love to place broken stuff in the typeref table
3851 verify_typeref_table (ctx);
3853 verify_typedef_table (ctx);
3855 verify_field_table (ctx);
3857 verify_method_table (ctx);
3859 verify_param_table (ctx);
3861 verify_interfaceimpl_table (ctx);
3863 verify_memberref_table (ctx);
3865 verify_constant_table (ctx);
3867 verify_cattr_table (ctx);
3869 verify_field_marshal_table (ctx);
3871 verify_decl_security_table (ctx);
3873 verify_class_layout_table (ctx);
3875 verify_field_layout_table (ctx);
3877 verify_standalonesig_table (ctx);
3879 verify_eventmap_table (ctx);
3881 verify_event_table (ctx);
3883 verify_propertymap_table (ctx);
3885 verify_property_table (ctx);
3887 verify_methodimpl_table (ctx);
3889 verify_moduleref_table (ctx);
3891 verify_typespec_table (ctx);
3893 verify_implmap_table (ctx);
3895 verify_fieldrva_table (ctx);
3897 verify_assembly_table (ctx);
3899 verify_assemblyref_table (ctx);
3901 verify_file_table (ctx);
3903 verify_exportedtype_table (ctx);
3905 verify_manifest_resource_table (ctx);
3907 verify_nested_class_table (ctx);
3909 verify_generic_param_table (ctx);
3911 verify_method_spec_table (ctx);
3913 verify_generic_param_constraint_table (ctx);
3915 verify_tables_data_global_constraints (ctx);
3919 init_verify_context (VerifyContext *ctx, MonoImage *image, gboolean report_error)
3921 memset (ctx, 0, sizeof (VerifyContext));
3923 ctx->report_error = report_error;
3924 ctx->report_warning = FALSE; //export this setting in the API
3926 ctx->size = image->raw_data_len;
3927 ctx->data = image->raw_data;
3931 cleanup_context (VerifyContext *ctx, GSList **error_list)
3933 g_free (ctx->sections);
3935 *error_list = ctx->errors;
3937 mono_free_verify_list (ctx->errors);
3942 cleanup_context_checked (VerifyContext *ctx, MonoError *error)
3944 g_free (ctx->sections);
3946 MonoVerifyInfo *info = (MonoVerifyInfo *)ctx->errors->data;
3947 mono_error_set_bad_image (error, ctx->image, "%s", info->message);
3948 mono_free_verify_list (ctx->errors);
3954 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3958 if (!mono_verifier_is_enabled_for_image (image))
3961 init_verify_context (&ctx, image, error_list != NULL);
3962 ctx.stage = STAGE_PE;
3964 verify_msdos_header (&ctx);
3966 verify_pe_header (&ctx);
3968 verify_pe_optional_header (&ctx);
3970 load_section_table (&ctx);
3972 load_data_directories (&ctx);
3974 verify_import_table (&ctx);
3976 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3977 verify_resources_table (&ctx);
3980 return cleanup_context (&ctx, error_list);
3984 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3988 if (!mono_verifier_is_enabled_for_image (image))
3991 init_verify_context (&ctx, image, error_list != NULL);
3992 ctx.stage = STAGE_CLI;
3994 verify_cli_header (&ctx);
3996 verify_metadata_header (&ctx);
3998 verify_tables_schema (&ctx);
4001 return cleanup_context (&ctx, error_list);
4006 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
4007 * Other verification checks are meant to be done lazily by the runtime. Those include:
4008 * blob items (signatures, method headers, custom attributes, etc)
4009 * type semantics related
4011 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
4013 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
4014 * operation still need more checking.
4017 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4021 if (!mono_verifier_is_enabled_for_image (image))
4024 init_verify_context (&ctx, image, error_list != NULL);
4025 ctx.stage = STAGE_TABLES;
4027 verify_tables_data (&ctx);
4029 return cleanup_context (&ctx, error_list);
4034 * Verifies all other constraints.
4037 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4041 if (!mono_verifier_is_enabled_for_image (image))
4044 init_verify_context (&ctx, image, error_list != NULL);
4045 ctx.stage = STAGE_TABLES;
4047 verify_typedef_table_full (&ctx);
4049 verify_field_table_full (&ctx);
4051 verify_method_table_full (&ctx);
4053 verify_memberref_table_full (&ctx);
4055 verify_cattr_table_full (&ctx);
4057 verify_field_marshal_table_full (&ctx);
4059 verify_decl_security_table_full (&ctx);
4061 verify_standalonesig_table_full (&ctx);
4063 verify_event_table_full (&ctx);
4065 verify_typespec_table_full (&ctx);
4067 verify_method_spec_table_full (&ctx);
4069 verify_tables_data_global_constraints_full (&ctx);
4072 return cleanup_context (&ctx, error_list);
4076 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4080 if (!mono_verifier_is_enabled_for_image (image))
4083 init_verify_context (&ctx, image, error_list != NULL);
4084 ctx.stage = STAGE_TABLES;
4086 is_valid_field_signature (&ctx, offset);
4087 return cleanup_context (&ctx, error_list);
4091 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4094 guint32 locals_token;
4096 if (!mono_verifier_is_enabled_for_image (image))
4099 init_verify_context (&ctx, image, error_list != NULL);
4100 ctx.stage = STAGE_TABLES;
4102 is_valid_method_header (&ctx, offset, &locals_token);
4104 guint32 sig_offset = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_STANDALONESIG], locals_token - 1, MONO_STAND_ALONE_SIGNATURE);
4105 is_valid_standalonesig_blob (&ctx, sig_offset);
4108 return cleanup_context (&ctx, error_list);
4112 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4118 if (!mono_verifier_is_enabled_for_image (image))
4121 init_verify_context (&ctx, image, TRUE);
4122 ctx.stage = STAGE_TABLES;
4124 is_valid_method_signature (&ctx, offset);
4125 /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
4126 return cleanup_context_checked (&ctx, error);
4130 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4134 if (!mono_verifier_is_enabled_for_image (image))
4137 init_verify_context (&ctx, image, error_list != NULL);
4138 ctx.stage = STAGE_TABLES;
4140 is_valid_memberref_method_signature (&ctx, offset);
4141 return cleanup_context (&ctx, error_list);
4145 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4149 if (!mono_verifier_is_enabled_for_image (image))
4152 init_verify_context (&ctx, image, error_list != NULL);
4153 ctx.stage = STAGE_TABLES;
4155 is_valid_field_signature (&ctx, offset);
4156 return cleanup_context (&ctx, error_list);
4160 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4164 if (!mono_verifier_is_enabled_for_image (image))
4167 init_verify_context (&ctx, image, error_list != NULL);
4168 ctx.stage = STAGE_TABLES;
4170 is_valid_standalonesig_blob (&ctx, offset);
4171 return cleanup_context (&ctx, error_list);
4175 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4179 if (!mono_verifier_is_enabled_for_image (image))
4182 init_verify_context (&ctx, image, error_list != NULL);
4183 ctx.stage = STAGE_TABLES;
4186 is_valid_typespec_blob (&ctx, offset);
4187 return cleanup_context (&ctx, error_list);
4191 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4195 if (!mono_verifier_is_enabled_for_image (image))
4198 init_verify_context (&ctx, image, error_list != NULL);
4199 ctx.stage = STAGE_TABLES;
4201 is_valid_methodspec_blob (&ctx, offset);
4202 return cleanup_context (&ctx, error_list);
4206 verify_user_string (VerifyContext *ctx, guint32 offset)
4208 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
4209 guint32 entry_size, bytes;
4211 if (heap_us.size < offset)
4212 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
4214 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
4215 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
4217 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
4218 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
4220 entry_size += bytes;
4222 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
4223 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
4227 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4231 if (!mono_verifier_is_enabled_for_image (image))
4234 init_verify_context (&ctx, image, error_list != NULL);
4235 ctx.stage = STAGE_TABLES;
4237 verify_user_string (&ctx, offset);
4239 return cleanup_context (&ctx, error_list);
4243 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4247 if (!mono_verifier_is_enabled_for_image (image))
4250 init_verify_context (&ctx, image, error_list != NULL);
4251 ctx.stage = STAGE_TABLES;
4253 is_valid_cattr_blob (&ctx, offset);
4255 return cleanup_context (&ctx, error_list);
4259 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4263 if (!mono_verifier_is_enabled_for_image (image))
4266 init_verify_context (&ctx, image, error_list != NULL);
4267 ctx.stage = STAGE_TABLES;
4269 is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
4271 return cleanup_context (&ctx, error_list);
4275 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4277 MonoMethodSignature *original_sig;
4278 if (!mono_verifier_is_enabled_for_image (image))
4281 original_sig = mono_method_signature (method);
4282 if (original_sig->call_convention == MONO_CALL_VARARG) {
4283 if (original_sig->hasthis != signature->hasthis)
4285 if (original_sig->call_convention != signature->call_convention)
4287 if (original_sig->explicit_this != signature->explicit_this)
4289 if (original_sig->pinvoke != signature->pinvoke)
4291 if (original_sig->sentinelpos != signature->sentinelpos)
4293 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4301 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4303 MonoTableInfo *table = &image->tables [MONO_TABLE_TYPEREF];
4304 guint32 data [MONO_TYPEREF_SIZE];
4308 if (!mono_verifier_is_enabled_for_image (image))
4311 if (row >= table->rows) {
4312 mono_error_set_bad_image (error, image, "Invalid typeref row %d - table has %d rows", row, table->rows);
4316 mono_metadata_decode_row (table, row, data, MONO_TYPEREF_SIZE);
4317 if (!is_valid_coded_index_with_image (image, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4318 mono_error_set_bad_image (error, image, "Invalid typeref row %d coded index 0x%08x", row, data [MONO_TYPEREF_SCOPE]);
4322 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4323 mono_error_set_bad_image (error, image, "The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", row);
4327 if (!data [MONO_TYPEREF_NAME] || !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAME], FALSE)) {
4328 mono_error_set_bad_image (error, image, "Invalid typeref row %d name token 0x%08x", row, data [MONO_TYPEREF_NAME]);
4332 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAMESPACE], FALSE)) {
4333 mono_error_set_bad_image (error, image, "Invalid typeref row %d namespace token 0x%08x", row, data [MONO_TYPEREF_NAMESPACE]);
4340 /*Perform additional verification including metadata ones*/
4342 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4344 MonoMethod *declaration, *body;
4345 MonoMethodSignature *body_sig, *decl_sig;
4346 MonoTableInfo *table = &image->tables [MONO_TABLE_METHODIMPL];
4347 guint32 data [MONO_METHODIMPL_SIZE];
4351 if (!mono_verifier_is_enabled_for_image (image))
4354 if (row >= table->rows) {
4355 mono_error_set_bad_image (error, image, "Invalid methodimpl row %d - table has %d rows", row, table->rows);
4359 mono_metadata_decode_row (table, row, data, MONO_METHODIMPL_SIZE);
4361 body = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_BODY], NULL, error);
4365 declaration = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_DECLARATION], NULL, error);
4370 mono_class_setup_supertypes (class);
4371 if (!mono_class_has_parent (class, body->klass)) {
4372 mono_error_set_bad_image (error, image, "Invalid methodimpl body doesn't belong to parent for row %x", row);
4376 if (!(body_sig = mono_method_signature_checked (body, error))) {
4380 if (!(decl_sig = mono_method_signature_checked (declaration, error))) {
4384 if (!mono_verifier_is_signature_compatible (decl_sig, body_sig)) {
4385 mono_error_set_bad_image (error, image, "Invalid methodimpl body signature not compatible with declaration row %x", row);
4394 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4400 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
4406 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
4412 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4418 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4424 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4430 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4437 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4443 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4449 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4455 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4461 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4467 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4473 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4480 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4487 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4494 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4500 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4505 #endif /* DISABLE_VERIFIER */