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));
1898 case MONO_TYPE_CLASS:
1899 if (klass != mono_defaults.systemtype_class)
1900 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1902 return is_valid_ser_string (ctx, _ptr, end);
1904 case MONO_TYPE_VALUETYPE:
1905 if (!klass || !klass->enumtype)
1906 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass->name_space, klass->name));
1908 klass = klass->element_class;
1909 type = klass->byval_arg.type;
1912 case MONO_TYPE_SZARRAY:
1913 mono_type = &klass->byval_arg;
1914 if (!is_valid_cattr_type (mono_type))
1915 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass->name_space, klass->name));
1916 if (!safe_read32 (element_count, ptr, end))
1917 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1918 if (element_count == 0xFFFFFFFFu) {
1922 for (i = 0; i < element_count; ++i) {
1923 if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
1929 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
1932 if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
1933 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
1934 *_ptr = ptr + elem_size;
1939 is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
1942 unsigned prolog = 0;
1944 MonoMethodSignature *sig;
1949 FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
1951 sig = mono_method_signature_checked (ctor, &error);
1952 if (!mono_error_ok (&error)) {
1953 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error)));
1954 mono_error_cleanup (&error);
1958 if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
1959 FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1963 if (!safe_read16 (prolog, ptr, end))
1964 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1967 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1969 args = sig->param_count;
1970 for (i = 0; i < args; ++i) {
1971 MonoType *arg_type = sig->params [i];
1972 if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
1976 if (!safe_read16 (num_named, ptr, end))
1977 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
1979 for (i = 0; i < num_named; ++i) {
1980 MonoType *type, simple_type = {{0}};
1983 if (!safe_read8 (kind, ptr, end))
1984 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
1985 if (kind != 0x53 && kind != 0x54)
1986 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
1987 if (!safe_read8 (kind, ptr, end))
1988 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
1990 if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
1991 simple_type.type = (MonoTypeEnum)kind;
1992 type = &simple_type;
1993 } else if (kind == MONO_TYPE_ENUM) {
1994 MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
1997 type = &klass->byval_arg;
1998 } else if (kind == 0x50) {
1999 type = &mono_defaults.systemtype_class->byval_arg;
2000 } else if (kind == 0x51) {
2001 type = &mono_defaults.object_class->byval_arg;
2002 } else if (kind == MONO_TYPE_SZARRAY) {
2005 if (!safe_read8 (etype, ptr, end))
2006 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
2008 if (etype == MONO_TYPE_ENUM) {
2009 klass = get_enum_by_encoded_name (ctx, &ptr, end);
2012 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
2013 klass = mono_defaults.systemtype_class;
2014 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
2015 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : (MonoTypeEnum)etype;
2016 klass = mono_class_from_mono_type (&simple_type);
2018 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
2020 type = &mono_array_class_get (klass, 1)->byval_arg;
2022 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
2025 if (!is_valid_ser_string (ctx, &ptr, end))
2028 if (!is_valid_fixed_param (ctx, type, &ptr, end))
2037 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
2039 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2040 //TODO do proper verification
2041 return blob.size >= 1 && blob.size - 1 >= offset;
2045 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
2047 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2048 //TODO do proper verification
2049 return blob.size >= 1 && blob.size - 1 >= offset;
2053 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
2056 unsigned signature = 0;
2057 const char *ptr = NULL, *end;
2059 if (!decode_signature_header (ctx, offset, &size, &ptr))
2060 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
2063 if (!safe_read8 (signature, ptr, end))
2064 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2067 if (signature == 0x07)
2068 return parse_locals_signature (ctx, &ptr, end);
2070 /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
2071 if (signature == 0x06)
2072 return parse_field (ctx, &ptr, end);
2074 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
2078 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
2081 const char *ptr = NULL, *end;
2083 if (!decode_signature_header (ctx, offset, &size, &ptr))
2084 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
2087 return parse_property_signature (ctx, &ptr, end);
2091 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
2094 const char *ptr = NULL, *end;
2097 if (!decode_signature_header (ctx, offset, &size, &ptr))
2098 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
2101 if (!parse_custom_mods (ctx, &ptr, end))
2104 if (!safe_read8 (type, ptr, end))
2105 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
2107 if (type == MONO_TYPE_BYREF) {
2108 if (!safe_read8 (type, ptr, end))
2109 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
2110 if (type == MONO_TYPE_TYPEDBYREF)
2111 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
2114 if (type == MONO_TYPE_TYPEDBYREF)
2118 return parse_type (ctx, &ptr, end);
2122 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
2125 const char *ptr = NULL, *end;
2127 unsigned count = 0, i;
2129 if (!decode_signature_header (ctx, offset, &size, &ptr))
2130 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
2133 if (!safe_read8 (type, ptr, end))
2134 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
2137 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
2139 if (!safe_read_cint (count, ptr, end))
2140 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
2143 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
2145 for (i = 0; i < count; ++i) {
2146 if (!parse_custom_mods (ctx, &ptr, end))
2148 if (!parse_type (ctx, &ptr, end))
2149 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
2155 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
2157 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2158 guint32 entry_size, bytes;
2160 if (blob.size < offset)
2163 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2166 if (entry_size < minsize)
2169 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
2171 entry_size += bytes;
2173 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
2177 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
2179 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2180 guint32 size, entry_size, bytes;
2182 if (blob.size < offset)
2183 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
2185 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2186 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
2188 if (type == MONO_TYPE_STRING) {
2189 //String is encoded as: compressed_int:len len *bytes
2192 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
2193 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
2199 case MONO_TYPE_BOOLEAN:
2204 case MONO_TYPE_CHAR:
2212 case MONO_TYPE_CLASS:
2222 g_assert_not_reached ();
2225 if (size != entry_size)
2226 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
2230 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
2231 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
2233 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
2234 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
2238 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
2239 //only 0x01, 0x40 and 0x80 are allowed
2240 #define SECTION_HEADER_INVALID_FLAGS 0x3E
2243 is_valid_method_header (VerifyContext *ctx, guint32 rva, guint32 *locals_token)
2245 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
2246 unsigned header = 0;
2247 unsigned fat_header = 0, size = 0, max_stack;
2248 const char *ptr = NULL, *end;
2252 if (offset == INVALID_ADDRESS)
2253 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
2255 ptr = ctx->data + offset;
2256 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
2258 if (!safe_read8 (header, ptr, end))
2259 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
2261 switch (header & 0x3) {
2264 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
2267 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
2268 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
2273 if (!safe_read16 (fat_header, ptr, end))
2274 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
2276 size = (fat_header >> 12) & 0xF;
2278 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
2280 if (!safe_read16 (max_stack, ptr, end))
2281 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
2283 if (!safe_read32 (code_size, ptr, end))
2284 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
2286 if (!safe_read32 (local_vars_tok, ptr, end))
2287 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
2289 if (local_vars_tok) {
2290 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
2291 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
2292 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
2293 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
2294 if (!(local_vars_tok & 0xFFFFFF))
2295 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature with zero index"));
2296 *locals_token = local_vars_tok & 0xFFFFFF;
2299 if (fat_header & FAT_HEADER_INVALID_FLAGS)
2300 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
2302 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
2303 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
2305 if (!(fat_header & 0x08))
2311 unsigned section_header = 0, section_size = 0;
2314 ptr = dword_align (ptr);
2315 if (!safe_read32 (section_header, ptr, end))
2316 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
2318 if (section_header & SECTION_HEADER_INVALID_FLAGS)
2319 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
2321 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
2322 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
2324 if (section_size < 4)
2325 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
2327 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
2328 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
2330 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
2331 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
2333 LAMEIMPL: MS emits section_size without accounting for header size.
2334 Mono does as the spec says. section_size is header + section
2335 MS's peverify happily accepts both.
2337 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
2338 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)));
2340 /* only verify the class token is verified as the rest is done by the IL verifier*/
2341 for (i = 0; i < clauses; ++i) {
2342 unsigned flags = *(unsigned char*)ptr;
2343 unsigned class_token = 0;
2344 ptr += (is_fat ? 20 : 8);
2345 if (!safe_read32 (class_token, ptr, end))
2346 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
2347 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
2348 guint table = mono_metadata_token_table (class_token);
2349 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
2350 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
2351 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
2352 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
2357 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
2364 verify_module_table (VerifyContext *ctx)
2366 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
2367 guint32 data [MONO_MODULE_SIZE];
2369 if (table->rows != 1)
2370 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
2372 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
2374 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
2375 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
2377 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
2378 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
2380 if (data [MONO_MODULE_ENC] != 0)
2381 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
2383 if (data [MONO_MODULE_ENCBASE] != 0)
2384 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
2388 verify_typeref_table (VerifyContext *ctx)
2390 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2394 for (i = 0; i < table->rows; ++i) {
2395 mono_verifier_verify_typeref_row (ctx->image, i, &error);
2396 add_from_mono_error (ctx, &error);
2400 /*bits 9,11,14,15,19,21,24-31 */
2401 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2403 verify_typedef_table (VerifyContext *ctx)
2405 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2406 guint32 data [MONO_TYPEDEF_SIZE];
2407 guint32 fieldlist = 1, methodlist = 1, visibility;
2410 if (table->rows == 0)
2411 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2413 for (i = 0; i < table->rows; ++i) {
2414 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2415 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2416 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2418 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2419 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2421 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2422 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2424 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2425 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2427 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2428 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2430 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2431 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2433 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2434 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2436 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2437 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2439 if (data [MONO_TYPEDEF_EXTENDS] && !get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2440 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d zero coded extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2442 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2443 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2444 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2445 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2447 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2448 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2450 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2451 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2453 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2454 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));
2456 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2457 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2459 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2460 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2462 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2463 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));
2465 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2466 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2471 verify_typedef_table_full (VerifyContext *ctx)
2473 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2474 guint32 data [MONO_TYPEDEF_SIZE];
2477 if (table->rows == 0)
2478 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2480 for (i = 0; i < table->rows; ++i) {
2481 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2484 /*XXX it's ok if <module> extends object, or anything at all, actually. */
2485 /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
2486 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2491 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2492 if (data [MONO_TYPEDEF_EXTENDS])
2493 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2495 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2496 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2500 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2503 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2511 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2513 verify_field_table (VerifyContext *ctx)
2515 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2516 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2519 module_field_list = (guint32)-1;
2520 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2521 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2522 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2525 for (i = 0; i < table->rows; ++i) {
2526 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2527 flags = data [MONO_FIELD_FLAGS];
2529 if (flags & INVALID_FIELD_FLAG_BITS)
2530 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2532 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2533 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2535 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2536 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2538 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2539 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2541 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2542 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2544 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2545 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2546 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2548 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2549 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2550 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2552 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2553 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2554 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2556 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2557 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2558 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2560 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2561 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2563 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2564 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2566 //TODO verify contant flag
2568 if (i + 1 < module_field_list) {
2569 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2570 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2571 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2572 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2573 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2579 verify_field_table_full (VerifyContext *ctx)
2581 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2582 guint32 data [MONO_FIELD_SIZE];
2585 for (i = 0; i < table->rows; ++i) {
2586 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2588 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2589 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2593 /*bits 8,9,10,11,13,14,15*/
2594 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2596 verify_method_table (VerifyContext *ctx)
2598 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2599 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2600 guint32 paramlist = 1;
2601 gboolean is_ctor, is_cctor;
2605 module_method_list = (guint32)-1;
2606 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2607 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2608 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2611 for (i = 0; i < table->rows; ++i) {
2612 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2613 rva = data [MONO_METHOD_RVA];
2614 implflags = data [MONO_METHOD_IMPLFLAGS];
2615 flags = data [MONO_METHOD_FLAGS];
2616 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2617 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2620 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2621 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2624 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2626 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2627 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2629 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2630 is_ctor = !strcmp (".ctor", name);
2631 is_cctor = !strcmp (".cctor", name);
2633 if ((is_ctor || is_cctor) &&
2634 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2635 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2637 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2638 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2640 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2641 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2642 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2643 if (flags & METHOD_ATTRIBUTE_FINAL)
2644 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2645 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2646 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2649 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2650 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2652 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2653 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2655 //XXX no checks against cas stuff 10,11,12,13)
2657 //TODO check iface with .ctor (15,16)
2659 if (i + 1 < module_method_list) {
2660 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2661 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2662 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2663 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2664 if (access == METHOD_ATTRIBUTE_FAMILY || access == METHOD_ATTRIBUTE_FAM_AND_ASSEM || access == METHOD_ATTRIBUTE_FAM_OR_ASSEM)
2665 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public, Private or Assembly", i));
2668 //TODO check valuetype for synchronized
2670 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2671 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2673 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2674 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2675 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2676 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2677 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2680 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2681 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2682 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2684 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2685 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2687 //TODO check signature contents
2690 if ((flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) || (implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
2691 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is either Abstract, InternalCall or PinvokeImpl", i));
2692 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2693 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2695 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2696 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2699 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2701 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2702 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2703 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2705 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2706 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2708 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2709 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2711 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2712 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2714 if (data [MONO_METHOD_PARAMLIST] == 0)
2715 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2717 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2718 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));
2720 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2721 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2723 paramlist = data [MONO_METHOD_PARAMLIST];
2729 verify_method_table_full (VerifyContext *ctx)
2731 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2732 guint32 data [MONO_METHOD_SIZE], rva, locals_token;
2735 for (i = 0; i < table->rows; ++i) {
2736 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2737 rva = data [MONO_METHOD_RVA];
2739 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2740 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2742 if (rva && !is_valid_method_header (ctx, rva, &locals_token))
2743 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2748 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2750 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2751 guint32 row = *current_method;
2752 guint32 paramlist, tmp;
2755 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2756 while (row < table->rows) {
2757 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2758 if (tmp > paramlist) {
2759 *current_method = row;
2760 return tmp - paramlist;
2765 /*no more methods, all params apply to the last one*/
2766 *current_method = table->rows;
2771 #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))
2773 verify_param_table (VerifyContext *ctx)
2775 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2776 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2777 gboolean first_param = TRUE;
2780 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2781 if (table->rows > 0)
2782 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2786 remaining_params = get_next_param_count (ctx, ¤t_method);
2788 for (i = 0; i < table->rows; ++i) {
2789 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2790 flags = data [MONO_PARAM_FLAGS];
2792 if (flags & INVALID_PARAM_FLAGS_BITS)
2793 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2795 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2796 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2797 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2799 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2800 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2803 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)
2804 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2806 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2807 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2809 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2810 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2812 first_param = FALSE;
2813 sequence = data [MONO_PARAM_SEQUENCE];
2814 if (--remaining_params == 0) {
2815 remaining_params = get_next_param_count (ctx, ¤t_method);
2822 verify_interfaceimpl_table (VerifyContext *ctx)
2824 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2825 guint32 data [MONO_INTERFACEIMPL_SIZE];
2828 for (i = 0; i < table->rows; ++i) {
2829 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2830 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2831 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_INTERFACEIMPL_CLASS]));
2833 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2834 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2836 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2837 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2842 verify_memberref_table (VerifyContext *ctx)
2844 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2845 guint32 data [MONO_MEMBERREF_SIZE];
2848 for (i = 0; i < table->rows; ++i) {
2849 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2851 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2852 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2854 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2855 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2857 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2858 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2860 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2861 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2867 verify_memberref_table_full (VerifyContext *ctx)
2869 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2870 guint32 data [MONO_MEMBERREF_SIZE];
2873 for (i = 0; i < table->rows; ++i) {
2874 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2876 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2877 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2882 verify_constant_table (VerifyContext *ctx)
2884 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2885 guint32 data [MONO_CONSTANT_SIZE], type;
2888 for (i = 0; i < table->rows; ++i) {
2889 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2890 type = data [MONO_CONSTANT_TYPE];
2892 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2893 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2895 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2896 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2898 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2899 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2901 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2902 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2907 verify_cattr_table (VerifyContext *ctx)
2909 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2910 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2913 for (i = 0; i < table->rows; ++i) {
2914 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2916 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2917 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2919 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]))
2920 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Type field 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2922 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2923 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2928 verify_cattr_table_full (VerifyContext *ctx)
2931 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2934 guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2937 for (i = 0; i < table->rows; ++i) {
2938 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2940 if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2941 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2943 mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2944 switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2945 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2946 mtoken |= MONO_TOKEN_METHOD_DEF;
2948 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2949 mtoken |= MONO_TOKEN_MEMBER_REF;
2952 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2955 ctor = mono_get_method_checked (ctx->image, mtoken, NULL, NULL, &error);
2958 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Could not load ctor due to %s", i, mono_error_get_message (&error)));
2959 mono_error_cleanup (&error);
2962 /*This can't fail since this is checked in is_valid_cattr_blob*/
2963 g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
2965 if (!is_valid_cattr_content (ctx, ctor, ptr, size))
2966 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2971 verify_field_marshal_table (VerifyContext *ctx)
2973 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2974 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2977 for (i = 0; i < table->rows; ++i) {
2978 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2980 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2981 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2983 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2984 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2986 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2987 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2989 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2990 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2995 verify_field_marshal_table_full (VerifyContext *ctx)
2997 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2998 guint32 data [MONO_FIELD_MARSHAL_SIZE];
3001 for (i = 0; i < table->rows; ++i) {
3002 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
3004 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
3005 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
3010 verify_decl_security_table (VerifyContext *ctx)
3012 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3013 guint32 data [MONO_DECL_SECURITY_SIZE];
3016 for (i = 0; i < table->rows; ++i) {
3017 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3019 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3020 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
3022 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3023 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
3025 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
3026 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
3031 verify_decl_security_table_full (VerifyContext *ctx)
3033 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3034 guint32 data [MONO_DECL_SECURITY_SIZE];
3037 for (i = 0; i < table->rows; ++i) {
3038 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3040 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
3041 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
3046 verify_class_layout_table (VerifyContext *ctx)
3048 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
3049 guint32 data [MONO_CLASS_LAYOUT_SIZE];
3052 for (i = 0; i < table->rows; ++i) {
3053 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
3055 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3056 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
3058 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
3070 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3076 verify_field_layout_table (VerifyContext *ctx)
3078 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3079 guint32 data [MONO_FIELD_LAYOUT_SIZE];
3082 for (i = 0; i < table->rows; ++i) {
3083 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
3085 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3086 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
3091 verify_standalonesig_table (VerifyContext *ctx)
3093 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3094 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3097 for (i = 0; i < table->rows; ++i) {
3098 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3100 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
3101 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3106 verify_standalonesig_table_full (VerifyContext *ctx)
3108 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3109 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3112 for (i = 0; i < table->rows; ++i) {
3113 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3115 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
3116 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3121 verify_eventmap_table (VerifyContext *ctx)
3123 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3124 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3127 for (i = 0; i < table->rows; ++i) {
3128 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
3130 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3131 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
3133 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
3134 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
3136 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
3140 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3142 verify_event_table (VerifyContext *ctx)
3144 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3145 guint32 data [MONO_EVENT_SIZE];
3148 for (i = 0; i < table->rows; ++i) {
3149 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3151 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
3152 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
3154 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
3155 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
3157 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
3158 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
3163 verify_event_table_full (VerifyContext *ctx)
3165 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3166 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
3167 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
3168 gboolean found_add, found_remove;
3171 for (i = 0; i < table->rows; ++i) {
3172 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3174 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
3175 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
3177 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
3179 //first we move to the first row for this event
3181 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3185 //now move forward looking for AddOn and RemoveOn rows
3186 found_add = found_remove = FALSE;
3187 while (idx < sema_table->rows) {
3188 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
3189 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
3191 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3193 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3194 found_remove = TRUE;
3195 if (found_add && found_remove)
3201 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3203 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no RemoveOn associated method", i));
3208 verify_propertymap_table (VerifyContext *ctx)
3210 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3211 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3214 for (i = 0; i < table->rows; ++i) {
3215 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
3217 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3218 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
3220 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
3221 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
3223 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
3227 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3229 verify_property_table (VerifyContext *ctx)
3231 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3232 guint32 data [MONO_PROPERTY_SIZE];
3235 for (i = 0; i < table->rows; ++i) {
3236 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
3238 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
3239 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
3241 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
3242 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
3244 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
3245 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
3247 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
3248 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
3249 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
3255 verify_methodimpl_table (VerifyContext *ctx)
3257 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3258 guint32 data [MONO_METHODIMPL_SIZE];
3261 for (i = 0; i < table->rows; ++i) {
3262 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3264 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3265 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3267 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3268 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3270 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3271 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3273 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3274 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3276 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3277 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3282 verify_moduleref_table (VerifyContext *ctx)
3284 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3285 guint32 data [MONO_MODULEREF_SIZE];
3288 for (i = 0; i < table->rows; ++i) {
3289 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
3291 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
3292 ADD_ERROR (ctx, g_strdup_printf ("Invalid ModuleRef row %d name field %08x", i, data [MONO_MODULEREF_NAME]));
3297 verify_typespec_table (VerifyContext *ctx)
3299 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3300 guint32 data [MONO_TYPESPEC_SIZE];
3303 for (i = 0; i < table->rows; ++i) {
3304 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3306 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
3307 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3312 verify_typespec_table_full (VerifyContext *ctx)
3314 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3315 guint32 data [MONO_TYPESPEC_SIZE];
3318 for (i = 0; i < table->rows; ++i) {
3319 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3320 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
3321 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
3322 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3327 #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))
3329 verify_implmap_table (VerifyContext *ctx)
3331 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3332 guint32 data [MONO_IMPLMAP_SIZE], cconv;
3335 for (i = 0; i < table->rows; ++i) {
3336 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
3338 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
3339 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
3341 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
3342 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
3343 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
3345 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3346 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
3348 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
3349 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
3351 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3352 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
3354 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
3355 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
3357 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows)
3358 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
3363 verify_fieldrva_table (VerifyContext *ctx)
3365 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3366 guint32 data [MONO_FIELD_RVA_SIZE];
3369 for (i = 0; i < table->rows; ++i) {
3370 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
3372 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
3373 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
3375 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3376 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
3380 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 14) | (1 << 15))
3382 verify_assembly_table (VerifyContext *ctx)
3384 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3385 guint32 data [MONO_ASSEMBLY_SIZE], hash;
3388 if (table->rows > 1)
3389 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
3391 for (i = 0; i < table->rows; ++i) {
3392 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
3394 hash = data [MONO_ASSEMBLY_HASH_ALG];
3395 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
3396 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
3398 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
3399 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3401 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
3402 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3404 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3405 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3407 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3408 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3412 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
3414 verify_assemblyref_table (VerifyContext *ctx)
3416 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3417 guint32 data [MONO_ASSEMBLYREF_SIZE];
3420 for (i = 0; i < table->rows; ++i) {
3421 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3423 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3424 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3426 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3427 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3429 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3430 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3432 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3433 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3435 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3436 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3440 #define INVALID_FILE_FLAGS_BITS ~(1)
3442 verify_file_table (VerifyContext *ctx)
3444 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3445 guint32 data [MONO_FILE_SIZE];
3448 for (i = 0; i < table->rows; ++i) {
3449 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3451 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3452 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3454 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3455 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3457 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3458 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3462 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3464 verify_exportedtype_table (VerifyContext *ctx)
3466 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3467 guint32 data [MONO_EXP_TYPE_SIZE];
3470 for (i = 0; i < table->rows; ++i) {
3471 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3473 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3474 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3476 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3477 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3479 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3480 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3482 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3483 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3485 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3486 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3488 /*nested type can't have a namespace*/
3489 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3490 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3494 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3496 verify_manifest_resource_table (VerifyContext *ctx)
3498 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
3499 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3500 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3501 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3504 resources_size = ch->ch_resources.size;
3506 for (i = 0; i < table->rows; ++i) {
3507 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3509 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3510 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3512 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3513 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3515 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3516 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3518 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3519 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3521 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3522 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3524 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3525 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])));
3527 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3528 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3530 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3531 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3536 verify_nested_class_table (VerifyContext *ctx)
3538 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3539 guint32 data [MONO_NESTED_CLASS_SIZE];
3542 for (i = 0; i < table->rows; ++i) {
3543 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3545 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3546 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3547 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3548 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3549 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3550 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3554 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3556 verify_generic_param_table (VerifyContext *ctx)
3558 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3559 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3560 int i, param_number = 0;
3562 for (i = 0; i < table->rows; ++i) {
3563 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3565 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3566 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3568 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3569 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3571 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3572 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3574 token = data [MONO_GENERICPARAM_OWNER];
3576 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3577 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3579 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3580 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3582 if (token != last_token) {
3587 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3588 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));
3595 verify_method_spec_table (VerifyContext *ctx)
3597 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3598 guint32 data [MONO_METHODSPEC_SIZE];
3601 for (i = 0; i < table->rows; ++i) {
3602 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3604 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3605 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3607 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3608 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3610 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3611 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3616 verify_method_spec_table_full (VerifyContext *ctx)
3618 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3619 guint32 data [MONO_METHODSPEC_SIZE];
3622 for (i = 0; i < table->rows; ++i) {
3623 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3625 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3626 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3631 verify_generic_param_constraint_table (VerifyContext *ctx)
3633 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3634 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3636 guint32 last_owner = 0, last_constraint = 0;
3638 for (i = 0; i < table->rows; ++i) {
3639 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3641 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3642 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3644 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3645 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3647 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3648 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3650 if (last_owner > data [MONO_GENPARCONSTRAINT_GENERICPAR])
3651 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]));
3653 if (last_owner == data [MONO_GENPARCONSTRAINT_GENERICPAR]) {
3654 if (last_constraint == data [MONO_GENPARCONSTRAINT_CONSTRAINT])
3655 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has duplicate constraint 0x%08x", i, last_constraint));
3657 last_owner = data [MONO_GENPARCONSTRAINT_GENERICPAR];
3659 last_constraint = data [MONO_GENPARCONSTRAINT_CONSTRAINT];
3666 const char *name_space;
3667 guint32 resolution_scope;
3671 typedef_hash (gconstpointer _key)
3673 const TypeDefUniqueId *key = (const TypeDefUniqueId *)_key;
3674 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3678 typedef_equals (gconstpointer _a, gconstpointer _b)
3680 const TypeDefUniqueId *a = (const TypeDefUniqueId *)_a;
3681 const TypeDefUniqueId *b = (const TypeDefUniqueId *)_b;
3682 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3686 verify_typedef_table_global_constraints (VerifyContext *ctx)
3689 guint32 data [MONO_TYPEDEF_SIZE];
3690 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3691 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3692 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3693 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3695 for (i = 0; i < table->rows; ++i) {
3697 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3698 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3700 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3701 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3702 type->resolution_scope = 0;
3704 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3705 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3706 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3707 g_assert (res >= 0);
3709 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3710 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3713 if (g_hash_table_lookup (unique_types, type)) {
3714 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));
3715 g_hash_table_destroy (unique_types);
3719 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3722 g_hash_table_destroy (unique_types);
3726 verify_typeref_table_global_constraints (VerifyContext *ctx)
3729 guint32 data [MONO_TYPEREF_SIZE];
3730 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3731 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3733 for (i = 0; i < table->rows; ++i) {
3734 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3735 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3737 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3738 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3739 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3741 if (g_hash_table_lookup (unique_types, type)) {
3742 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));
3743 g_hash_table_destroy (unique_types);
3747 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3750 g_hash_table_destroy (unique_types);
3755 guint32 method_declaration;
3756 } MethodImplUniqueId;
3759 methodimpl_hash (gconstpointer _key)
3761 const MethodImplUniqueId *key = (const MethodImplUniqueId *)_key;
3762 return key->klass ^ key->method_declaration;
3766 methodimpl_equals (gconstpointer _a, gconstpointer _b)
3768 const MethodImplUniqueId *a = (const MethodImplUniqueId *)_a;
3769 const MethodImplUniqueId *b = (const MethodImplUniqueId *)_b;
3770 return a->klass == b->klass && a->method_declaration == b->method_declaration;
3774 verify_methodimpl_table_global_constraints (VerifyContext *ctx)
3777 guint32 data [MONO_METHODIMPL_SIZE];
3778 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3779 GHashTable *unique_impls = g_hash_table_new_full (&methodimpl_hash, &methodimpl_equals, g_free, NULL);
3781 for (i = 0; i < table->rows; ++i) {
3782 MethodImplUniqueId *impl = g_new (MethodImplUniqueId, 1);
3783 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3785 impl->klass = data [MONO_METHODIMPL_CLASS];
3786 impl->method_declaration = data [MONO_METHODIMPL_DECLARATION];
3788 if (g_hash_table_lookup (unique_impls, impl)) {
3789 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));
3790 g_hash_table_destroy (unique_impls);
3794 g_hash_table_insert (unique_impls, impl, GUINT_TO_POINTER (1));
3797 g_hash_table_destroy (unique_impls);
3802 verify_tables_data_global_constraints (VerifyContext *ctx)
3804 verify_typedef_table_global_constraints (ctx);
3808 verify_tables_data_global_constraints_full (VerifyContext *ctx)
3810 verify_typeref_table (ctx);
3811 verify_typeref_table_global_constraints (ctx);
3812 verify_methodimpl_table_global_constraints (ctx);
3816 verify_tables_data (VerifyContext *ctx)
3818 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3819 guint32 size = 0, tables_offset;
3822 for (i = 0; i < 0x2D; ++i) {
3823 MonoTableInfo *table = &ctx->image->tables [i];
3825 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3826 if (tmp_size < size) {
3834 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3836 tables_offset = ctx->image->tables_base - ctx->data;
3837 if (!bounds_check_offset (&tables_area, tables_offset, size))
3838 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)));
3840 verify_module_table (ctx);
3842 /*Obfuscators love to place broken stuff in the typeref table
3843 verify_typeref_table (ctx);
3845 verify_typedef_table (ctx);
3847 verify_field_table (ctx);
3849 verify_method_table (ctx);
3851 verify_param_table (ctx);
3853 verify_interfaceimpl_table (ctx);
3855 verify_memberref_table (ctx);
3857 verify_constant_table (ctx);
3859 verify_cattr_table (ctx);
3861 verify_field_marshal_table (ctx);
3863 verify_decl_security_table (ctx);
3865 verify_class_layout_table (ctx);
3867 verify_field_layout_table (ctx);
3869 verify_standalonesig_table (ctx);
3871 verify_eventmap_table (ctx);
3873 verify_event_table (ctx);
3875 verify_propertymap_table (ctx);
3877 verify_property_table (ctx);
3879 verify_methodimpl_table (ctx);
3881 verify_moduleref_table (ctx);
3883 verify_typespec_table (ctx);
3885 verify_implmap_table (ctx);
3887 verify_fieldrva_table (ctx);
3889 verify_assembly_table (ctx);
3891 verify_assemblyref_table (ctx);
3893 verify_file_table (ctx);
3895 verify_exportedtype_table (ctx);
3897 verify_manifest_resource_table (ctx);
3899 verify_nested_class_table (ctx);
3901 verify_generic_param_table (ctx);
3903 verify_method_spec_table (ctx);
3905 verify_generic_param_constraint_table (ctx);
3907 verify_tables_data_global_constraints (ctx);
3911 init_verify_context (VerifyContext *ctx, MonoImage *image, gboolean report_error)
3913 memset (ctx, 0, sizeof (VerifyContext));
3915 ctx->report_error = report_error;
3916 ctx->report_warning = FALSE; //export this setting in the API
3918 ctx->size = image->raw_data_len;
3919 ctx->data = image->raw_data;
3923 cleanup_context (VerifyContext *ctx, GSList **error_list)
3925 g_free (ctx->sections);
3927 *error_list = ctx->errors;
3929 mono_free_verify_list (ctx->errors);
3934 cleanup_context_checked (VerifyContext *ctx, MonoError *error)
3936 g_free (ctx->sections);
3938 MonoVerifyInfo *info = (MonoVerifyInfo *)ctx->errors->data;
3939 mono_error_set_bad_image (error, ctx->image, "%s", info->message);
3940 mono_free_verify_list (ctx->errors);
3946 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3950 if (!mono_verifier_is_enabled_for_image (image))
3953 init_verify_context (&ctx, image, error_list != NULL);
3954 ctx.stage = STAGE_PE;
3956 verify_msdos_header (&ctx);
3958 verify_pe_header (&ctx);
3960 verify_pe_optional_header (&ctx);
3962 load_section_table (&ctx);
3964 load_data_directories (&ctx);
3966 verify_import_table (&ctx);
3968 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3969 verify_resources_table (&ctx);
3972 return cleanup_context (&ctx, error_list);
3976 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3980 if (!mono_verifier_is_enabled_for_image (image))
3983 init_verify_context (&ctx, image, error_list != NULL);
3984 ctx.stage = STAGE_CLI;
3986 verify_cli_header (&ctx);
3988 verify_metadata_header (&ctx);
3990 verify_tables_schema (&ctx);
3993 return cleanup_context (&ctx, error_list);
3998 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3999 * Other verification checks are meant to be done lazily by the runtime. Those include:
4000 * blob items (signatures, method headers, custom attributes, etc)
4001 * type semantics related
4003 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
4005 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
4006 * operation still need more checking.
4009 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4013 if (!mono_verifier_is_enabled_for_image (image))
4016 init_verify_context (&ctx, image, error_list != NULL);
4017 ctx.stage = STAGE_TABLES;
4019 verify_tables_data (&ctx);
4021 return cleanup_context (&ctx, error_list);
4026 * Verifies all other constraints.
4029 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4033 if (!mono_verifier_is_enabled_for_image (image))
4036 init_verify_context (&ctx, image, error_list != NULL);
4037 ctx.stage = STAGE_TABLES;
4039 verify_typedef_table_full (&ctx);
4041 verify_field_table_full (&ctx);
4043 verify_method_table_full (&ctx);
4045 verify_memberref_table_full (&ctx);
4047 verify_cattr_table_full (&ctx);
4049 verify_field_marshal_table_full (&ctx);
4051 verify_decl_security_table_full (&ctx);
4053 verify_standalonesig_table_full (&ctx);
4055 verify_event_table_full (&ctx);
4057 verify_typespec_table_full (&ctx);
4059 verify_method_spec_table_full (&ctx);
4061 verify_tables_data_global_constraints_full (&ctx);
4064 return cleanup_context (&ctx, error_list);
4068 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4072 if (!mono_verifier_is_enabled_for_image (image))
4075 init_verify_context (&ctx, image, error_list != NULL);
4076 ctx.stage = STAGE_TABLES;
4078 is_valid_field_signature (&ctx, offset);
4079 return cleanup_context (&ctx, error_list);
4083 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4086 guint32 locals_token;
4088 if (!mono_verifier_is_enabled_for_image (image))
4091 init_verify_context (&ctx, image, error_list != NULL);
4092 ctx.stage = STAGE_TABLES;
4094 is_valid_method_header (&ctx, offset, &locals_token);
4096 guint32 sig_offset = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_STANDALONESIG], locals_token - 1, MONO_STAND_ALONE_SIGNATURE);
4097 is_valid_standalonesig_blob (&ctx, sig_offset);
4100 return cleanup_context (&ctx, error_list);
4104 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4110 if (!mono_verifier_is_enabled_for_image (image))
4113 init_verify_context (&ctx, image, TRUE);
4114 ctx.stage = STAGE_TABLES;
4116 is_valid_method_signature (&ctx, offset);
4117 /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
4118 return cleanup_context_checked (&ctx, error);
4122 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4126 if (!mono_verifier_is_enabled_for_image (image))
4129 init_verify_context (&ctx, image, error_list != NULL);
4130 ctx.stage = STAGE_TABLES;
4132 is_valid_memberref_method_signature (&ctx, offset);
4133 return cleanup_context (&ctx, error_list);
4137 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4141 if (!mono_verifier_is_enabled_for_image (image))
4144 init_verify_context (&ctx, image, error_list != NULL);
4145 ctx.stage = STAGE_TABLES;
4147 is_valid_field_signature (&ctx, offset);
4148 return cleanup_context (&ctx, error_list);
4152 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4156 if (!mono_verifier_is_enabled_for_image (image))
4159 init_verify_context (&ctx, image, error_list != NULL);
4160 ctx.stage = STAGE_TABLES;
4162 is_valid_standalonesig_blob (&ctx, offset);
4163 return cleanup_context (&ctx, error_list);
4167 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4171 if (!mono_verifier_is_enabled_for_image (image))
4174 init_verify_context (&ctx, image, error_list != NULL);
4175 ctx.stage = STAGE_TABLES;
4178 is_valid_typespec_blob (&ctx, offset);
4179 return cleanup_context (&ctx, error_list);
4183 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4187 if (!mono_verifier_is_enabled_for_image (image))
4190 init_verify_context (&ctx, image, error_list != NULL);
4191 ctx.stage = STAGE_TABLES;
4193 is_valid_methodspec_blob (&ctx, offset);
4194 return cleanup_context (&ctx, error_list);
4198 verify_user_string (VerifyContext *ctx, guint32 offset)
4200 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
4201 guint32 entry_size, bytes;
4203 if (heap_us.size < offset)
4204 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
4206 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
4207 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
4209 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
4210 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
4212 entry_size += bytes;
4214 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
4215 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
4219 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4223 if (!mono_verifier_is_enabled_for_image (image))
4226 init_verify_context (&ctx, image, error_list != NULL);
4227 ctx.stage = STAGE_TABLES;
4229 verify_user_string (&ctx, offset);
4231 return cleanup_context (&ctx, error_list);
4235 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4239 if (!mono_verifier_is_enabled_for_image (image))
4242 init_verify_context (&ctx, image, error_list != NULL);
4243 ctx.stage = STAGE_TABLES;
4245 is_valid_cattr_blob (&ctx, offset);
4247 return cleanup_context (&ctx, error_list);
4251 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4255 if (!mono_verifier_is_enabled_for_image (image))
4258 init_verify_context (&ctx, image, error_list != NULL);
4259 ctx.stage = STAGE_TABLES;
4261 is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
4263 return cleanup_context (&ctx, error_list);
4267 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4269 MonoMethodSignature *original_sig;
4270 if (!mono_verifier_is_enabled_for_image (image))
4273 original_sig = mono_method_signature (method);
4274 if (original_sig->call_convention == MONO_CALL_VARARG) {
4275 if (original_sig->hasthis != signature->hasthis)
4277 if (original_sig->call_convention != signature->call_convention)
4279 if (original_sig->explicit_this != signature->explicit_this)
4281 if (original_sig->pinvoke != signature->pinvoke)
4283 if (original_sig->sentinelpos != signature->sentinelpos)
4285 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4293 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4295 MonoTableInfo *table = &image->tables [MONO_TABLE_TYPEREF];
4296 guint32 data [MONO_TYPEREF_SIZE];
4300 if (!mono_verifier_is_enabled_for_image (image))
4303 if (row >= table->rows) {
4304 mono_error_set_bad_image (error, image, "Invalid typeref row %d - table has %d rows", row, table->rows);
4308 mono_metadata_decode_row (table, row, data, MONO_TYPEREF_SIZE);
4309 if (!is_valid_coded_index_with_image (image, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4310 mono_error_set_bad_image (error, image, "Invalid typeref row %d coded index 0x%08x", row, data [MONO_TYPEREF_SCOPE]);
4314 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4315 mono_error_set_bad_image (error, image, "The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", row);
4319 if (!data [MONO_TYPEREF_NAME] || !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAME], FALSE)) {
4320 mono_error_set_bad_image (error, image, "Invalid typeref row %d name token 0x%08x", row, data [MONO_TYPEREF_NAME]);
4324 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAMESPACE], FALSE)) {
4325 mono_error_set_bad_image (error, image, "Invalid typeref row %d namespace token 0x%08x", row, data [MONO_TYPEREF_NAMESPACE]);
4332 /*Perform additional verification including metadata ones*/
4334 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4336 MonoMethod *declaration, *body;
4337 MonoMethodSignature *body_sig, *decl_sig;
4338 MonoTableInfo *table = &image->tables [MONO_TABLE_METHODIMPL];
4339 guint32 data [MONO_METHODIMPL_SIZE];
4343 if (!mono_verifier_is_enabled_for_image (image))
4346 if (row >= table->rows) {
4347 mono_error_set_bad_image (error, image, "Invalid methodimpl row %d - table has %d rows", row, table->rows);
4351 mono_metadata_decode_row (table, row, data, MONO_METHODIMPL_SIZE);
4353 body = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_BODY], NULL, error);
4357 declaration = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_DECLARATION], NULL, error);
4362 mono_class_setup_supertypes (class);
4363 if (!mono_class_has_parent (class, body->klass)) {
4364 mono_error_set_bad_image (error, image, "Invalid methodimpl body doesn't belong to parent for row %x", row);
4368 if (!(body_sig = mono_method_signature_checked (body, error))) {
4372 if (!(decl_sig = mono_method_signature_checked (declaration, error))) {
4376 if (!mono_verifier_is_signature_compatible (decl_sig, body_sig)) {
4377 mono_error_set_bad_image (error, image, "Invalid methodimpl body signature not compatible with declaration row %x", row);
4386 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4392 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
4398 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
4404 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4410 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4416 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4422 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4429 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4435 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4441 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4447 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4453 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4459 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4465 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4472 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4479 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4486 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4492 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4497 #endif /* DISABLE_VERIFIER */