2 * metadata-verify.c: Metadata verfication support
5 * Mono Project (http://www.mono-project.com)
7 * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
9 #include <mono/metadata/object-internals.h>
10 #include <mono/metadata/verify.h>
11 #include <mono/metadata/verify-internals.h>
12 #include <mono/metadata/opcodes.h>
13 #include <mono/metadata/tabledefs.h>
14 #include <mono/metadata/reflection.h>
15 #include <mono/metadata/debug-helpers.h>
16 #include <mono/metadata/mono-endian.h>
17 #include <mono/metadata/metadata.h>
18 #include <mono/metadata/metadata-internals.h>
19 #include <mono/metadata/class-internals.h>
20 #include <mono/metadata/tokentype.h>
21 #include <mono/metadata/security-manager.h>
22 #include <mono/metadata/security-core-clr.h>
23 #include <mono/metadata/cil-coff.h>
24 #include <mono/metadata/attrdefs.h>
25 #include <mono/utils/strenc.h>
30 #ifndef DISABLE_VERIFIER
32 TODO add fail fast mode
33 TODO add PE32+ support
34 TODO verify the entry point RVA and content.
35 TODO load_section_table and load_data_directories must take PE32+ into account
36 TODO add section relocation support
37 TODO verify the relocation table, since we really don't use, no need so far.
38 TODO do full PECOFF resources verification
39 TODO verify in the CLI header entry point and resources
40 TODO implement null token typeref validation
41 TODO verify table wide invariants for typedef (sorting and uniqueness)
42 TODO implement proper authenticode data directory validation
43 TODO verify properties that require multiple tables to be valid
44 FIXME use subtraction based bounds checking to avoid overflows
45 FIXME get rid of metadata_streams and other fields from VerifyContext
48 #ifdef MONO_VERIFIER_DEBUG
49 #define VERIFIER_DEBUG(code) do { code; } while (0)
51 #define VERIFIER_DEBUG(code)
54 #define INVALID_OFFSET ((guint32)-1)
55 #define INVALID_ADDRESS 0xffffffff
65 RESOURCE_TABLE_IDX
= 2,
66 CERTIFICATE_TABLE_IDX
= 4,
67 RELOCATION_TABLE_IDX
= 5,
81 #define INVALID_TABLE (0xFF)
82 /*format: number of bits, number of tables, tables{n. tables} */
83 const static unsigned char coded_index_desc
[] = {
84 #define TYPEDEF_OR_REF_DESC (0)
91 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
98 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
106 MONO_TABLE_INTERFACEIMPL
,
107 MONO_TABLE_MEMBERREF
,
109 MONO_TABLE_DECLSECURITY
,
112 MONO_TABLE_STANDALONESIG
,
113 MONO_TABLE_MODULEREF
,
116 MONO_TABLE_ASSEMBLYREF
,
118 MONO_TABLE_EXPORTEDTYPE
,
119 MONO_TABLE_MANIFESTRESOURCE
,
120 MONO_TABLE_GENERICPARAM
,
122 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
128 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
135 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
144 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
150 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
154 MONO_TABLE_MEMBERREF
,
156 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
162 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
166 MONO_TABLE_ASSEMBLYREF
,
167 MONO_TABLE_EXPORTEDTYPE
,
169 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
175 MONO_TABLE_MEMBERREF
,
178 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
182 MONO_TABLE_MODULEREF
,
183 MONO_TABLE_ASSEMBLYREF
,
186 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
196 guint32 translated_offset
;
208 guint32 rellocationsRVA
;
209 guint16 numberOfRelocations
;
224 gboolean report_error
;
225 gboolean report_warning
;
228 DataDirectory data_directories
[16];
229 guint32 section_count
;
230 SectionHeader
*sections
;
232 OffsetAndSize metadata_streams
[5]; //offset from begin of the image
235 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
237 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
238 vinfo->info.status = __status; \
239 vinfo->info.message = ( __msg); \
240 vinfo->exception_type = (__exception); \
241 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
244 #define ADD_WARNING(__ctx, __msg) \
246 if ((__ctx)->report_warning) { \
247 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
248 (__ctx)->valid = 0; \
253 #define ADD_ERROR_NO_RETURN(__ctx, __msg) \
255 if ((__ctx)->report_error) \
256 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
257 (__ctx)->valid = 0; \
260 #define ADD_ERROR(__ctx, __msg) \
262 if ((__ctx)->report_error) \
263 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
264 (__ctx)->valid = 0; \
268 #define FAIL(__ctx, __msg) \
270 if ((__ctx)->report_error) \
271 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
272 (__ctx)->valid = 0; \
276 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
278 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
280 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
281 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
283 #if SIZEOF_VOID_P == 4
284 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
286 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
289 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
290 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
293 dword_align (const char *ptr
)
295 #if SIZEOF_VOID_P == 8
296 return (const char *) (((guint64
) (ptr
+ 3)) & ~3);
298 return (const char *) (((guint32
) (ptr
+ 3)) & ~3);
303 pe_signature_offset (VerifyContext
*ctx
)
305 return read32 (ctx
->data
+ 0x3c);
309 pe_header_offset (VerifyContext
*ctx
)
311 return read32 (ctx
->data
+ 0x3c) + 4;
315 bounds_check_virtual_address (VerifyContext
*ctx
, guint32 rva
, guint32 size
)
319 if (rva
+ size
< rva
) //overflow
322 if (ctx
->stage
> STAGE_PE
) {
323 MonoCLIImageInfo
*iinfo
= ctx
->image
->image_info
;
324 const int top
= iinfo
->cli_section_count
;
325 MonoSectionTable
*tables
= iinfo
->cli_section_tables
;
328 for (i
= 0; i
< top
; i
++) {
329 guint32 base
= tables
->st_virtual_address
;
330 guint32 end
= base
+ tables
->st_raw_data_size
;
332 if (rva
>= base
&& rva
+ size
<= end
)
335 /*if ((addr >= tables->st_virtual_address) &&
336 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
338 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
348 for (i
= 0; i
< ctx
->section_count
; ++i
) {
349 guint32 base
= ctx
->sections
[i
].baseRVA
;
350 guint32 end
= ctx
->sections
[i
].baseRVA
+ ctx
->sections
[i
].size
;
351 if (rva
>= base
&& rva
+ size
<= end
)
358 bounds_check_datadir (DataDirectory
*dir
, guint32 offset
, guint32 size
)
360 if (dir
->translated_offset
> offset
)
362 if (dir
->size
< size
)
364 return offset
+ size
<= dir
->translated_offset
+ dir
->size
;
368 bounds_check_offset (OffsetAndSize
*off
, guint32 offset
, guint32 size
)
370 if (off
->offset
> offset
)
373 if (off
->size
< size
)
376 return offset
+ size
<= off
->offset
+ off
->size
;
380 translate_rva (VerifyContext
*ctx
, guint32 rva
)
384 if (ctx
->stage
> STAGE_PE
)
385 return mono_cli_rva_image_map (ctx
->image
, rva
);
390 for (i
= 0; i
< ctx
->section_count
; ++i
) {
391 guint32 base
= ctx
->sections
[i
].baseRVA
;
392 guint32 end
= ctx
->sections
[i
].baseRVA
+ ctx
->sections
[i
].size
;
393 if (rva
>= base
&& rva
<= end
) {
394 guint32 res
= (rva
- base
) + ctx
->sections
[i
].baseOffset
;
396 return res
>= ctx
->size
? INVALID_OFFSET
: res
;
400 return INVALID_OFFSET
;
404 verify_msdos_header (VerifyContext
*ctx
)
408 ADD_ERROR (ctx
, g_strdup ("Not enough space for the MS-DOS header"));
409 if (ctx
->data
[0] != 0x4d || ctx
->data
[1] != 0x5a)
410 ADD_ERROR (ctx
, g_strdup ("Invalid MS-DOS watermark"));
411 lfanew
= pe_signature_offset (ctx
);
412 if (lfanew
> ctx
->size
- 4)
413 ADD_ERROR (ctx
, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
417 verify_pe_header (VerifyContext
*ctx
)
419 guint32 offset
= pe_signature_offset (ctx
);
420 const char *pe_header
= ctx
->data
+ offset
;
421 if (pe_header
[0] != 'P' || pe_header
[1] != 'E' ||pe_header
[2] != 0 ||pe_header
[3] != 0)
422 ADD_ERROR (ctx
, g_strdup ("Invalid PE header watermark"));
426 if (offset
> ctx
->size
- 20)
427 ADD_ERROR (ctx
, g_strdup ("File with truncated pe header"));
428 if (read16 (pe_header
) != 0x14c)
429 ADD_ERROR (ctx
, g_strdup ("Invalid PE header Machine value"));
433 verify_pe_optional_header (VerifyContext
*ctx
)
435 guint32 offset
= pe_header_offset (ctx
);
436 guint32 header_size
, file_alignment
;
437 const char *pe_header
= ctx
->data
+ offset
;
438 const char *pe_optional_header
= pe_header
+ 20;
440 header_size
= read16 (pe_header
+ 16);
443 if (header_size
< 2) /*must be at least 2 or we won't be able to read magic*/
444 ADD_ERROR (ctx
, g_strdup ("Invalid PE optional header size"));
446 if (offset
> ctx
->size
- header_size
|| header_size
> ctx
->size
)
447 ADD_ERROR (ctx
, g_strdup ("Invalid PE optional header size"));
449 if (read16 (pe_optional_header
) == 0x10b) {
450 if (header_size
!= 224)
451 ADD_ERROR (ctx
, g_strdup_printf ("Invalid optional header size %d", header_size
));
453 /* LAMESPEC MS plays around this value and ignore it during validation
454 if (read32 (pe_optional_header + 28) != 0x400000)
455 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
456 if (read32 (pe_optional_header
+ 32) != 0x2000)
457 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header
+ 32)));
458 file_alignment
= read32 (pe_optional_header
+ 36);
459 if (file_alignment
!= 0x200 && file_alignment
!= 0x1000)
460 ADD_ERROR (ctx
, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment
));
461 /* All the junk in the middle is irrelevant, specially for mono. */
462 if (read32 (pe_optional_header
+ 92) > 0x10)
463 ADD_ERROR (ctx
, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header
+ 92)));
465 if (read16 (pe_optional_header
) == 0x20B)
466 ADD_ERROR (ctx
, g_strdup ("Metadata verifier doesn't handle PE32+"));
468 ADD_ERROR (ctx
, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header
)));
473 load_section_table (VerifyContext
*ctx
)
476 SectionHeader
*sections
;
477 guint32 offset
= pe_header_offset (ctx
);
478 const char *ptr
= ctx
->data
+ offset
;
479 guint16 num_sections
= ctx
->section_count
= read16 (ptr
+ 2);
481 offset
+= 244;/*FIXME, this constant is different under PE32+*/
484 if (num_sections
* 40 > ctx
->size
- offset
)
485 ADD_ERROR (ctx
, g_strdup ("Invalid PE optional header size"));
487 sections
= ctx
->sections
= g_new0 (SectionHeader
, num_sections
);
488 for (i
= 0; i
< num_sections
; ++i
) {
489 sections
[i
].size
= read32 (ptr
+ 8);
490 sections
[i
].baseRVA
= read32 (ptr
+ 12);
491 sections
[i
].baseOffset
= read32 (ptr
+ 20);
492 sections
[i
].rellocationsRVA
= read32 (ptr
+ 24);
493 sections
[i
].numberOfRelocations
= read16 (ptr
+ 32);
497 ptr
= ctx
->data
+ offset
; /*reset it to the beggining*/
498 for (i
= 0; i
< num_sections
; ++i
) {
499 guint32 raw_size
, flags
;
500 if (sections
[i
].baseOffset
== 0)
501 ADD_ERROR (ctx
, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
502 if (sections
[i
].baseOffset
>= ctx
->size
)
503 ADD_ERROR (ctx
, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections
[i
].baseOffset
));
504 if (sections
[i
].size
> ctx
->size
- sections
[i
].baseOffset
)
505 ADD_ERROR (ctx
, g_strdup ("Invalid VirtualSize points beyond EOF"));
507 raw_size
= read32 (ptr
+ 16);
508 if (raw_size
< sections
[i
].size
)
509 ADD_ERROR (ctx
, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
511 if (raw_size
> ctx
->size
- sections
[i
].baseOffset
)
512 ADD_ERROR (ctx
, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size
));
514 if (sections
[i
].rellocationsRVA
|| sections
[i
].numberOfRelocations
)
515 ADD_ERROR (ctx
, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
517 flags
= read32 (ptr
+ 36);
518 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
519 if (flags
== 0 || (flags
& ~0xFE0000E0) != 0)
520 ADD_ERROR (ctx
, g_strdup_printf ("Invalid section flags %x", flags
));
527 is_valid_data_directory (int i
)
529 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
530 return i
== 1 || i
== 2 || i
== 5 || i
== 12 || i
== 14 || i
== 4 || i
== 6;
534 load_data_directories (VerifyContext
*ctx
)
536 guint32 offset
= pe_header_offset (ctx
) + 116; /*FIXME, this constant is different under PE32+*/
537 const char *ptr
= ctx
->data
+ offset
;
540 for (i
= 0; i
< 16; ++i
) {
541 guint32 rva
= read32 (ptr
);
542 guint32 size
= read32 (ptr
+ 4);
544 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
545 if (i
== CERTIFICATE_TABLE_IDX
) {
549 if ((rva
!= 0 || size
!= 0) && !is_valid_data_directory (i
))
550 ADD_ERROR (ctx
, g_strdup_printf ("Invalid data directory %d", i
));
552 if (rva
!= 0 && !bounds_check_virtual_address (ctx
, rva
, size
))
553 ADD_ERROR (ctx
, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i
, rva
, size
));
555 ctx
->data_directories
[i
].rva
= rva
;
556 ctx
->data_directories
[i
].size
= size
;
557 ctx
->data_directories
[i
].translated_offset
= translate_rva (ctx
, rva
);
563 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
565 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
568 verify_hint_name_table (VerifyContext
*ctx
, guint32 import_rva
, const char *table_name
)
571 guint32 hint_table_rva
;
573 import_rva
= translate_rva (ctx
, import_rva
);
574 g_assert (import_rva
!= INVALID_OFFSET
);
576 hint_table_rva
= read32 (ctx
->data
+ import_rva
);
577 if (!bounds_check_virtual_address (ctx
, hint_table_rva
, SIZE_OF_CORMAIN
+ 2))
578 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva
, table_name
));
580 hint_table_rva
= translate_rva (ctx
, hint_table_rva
);
581 g_assert (hint_table_rva
!= INVALID_OFFSET
);
582 ptr
= ctx
->data
+ hint_table_rva
+ 2;
584 if (memcmp ("_CorExeMain", ptr
, SIZE_OF_CORMAIN
) && memcmp ("_CorDllMain", ptr
, SIZE_OF_CORMAIN
)) {
585 char name
[SIZE_OF_CORMAIN
];
586 memcpy (name
, ptr
, SIZE_OF_CORMAIN
);
587 name
[SIZE_OF_CORMAIN
- 1] = 0;
588 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Hint / Name: '%s'", name
));
593 verify_import_table (VerifyContext
*ctx
)
595 DataDirectory it
= ctx
->data_directories
[IMPORT_TABLE_IDX
];
596 guint32 offset
= it
.translated_offset
;
597 const char *ptr
= ctx
->data
+ offset
;
598 guint32 name_rva
, ilt_rva
, iat_rva
;
600 g_assert (offset
!= INVALID_OFFSET
);
603 ADD_ERROR (ctx
, g_strdup_printf ("Import table size %d is smaller than 40", it
.size
));
605 ilt_rva
= read32 (ptr
);
606 if (ilt_rva
&& !bounds_check_virtual_address (ctx
, ilt_rva
, 8))
607 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva
));
609 name_rva
= read32 (ptr
+ 12);
610 if (name_rva
&& !bounds_check_virtual_address (ctx
, name_rva
, SIZE_OF_MSCOREE
))
611 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva
));
613 iat_rva
= read32 (ptr
+ 16);
615 if (!bounds_check_virtual_address (ctx
, iat_rva
, 8))
616 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva
));
618 if (iat_rva
!= ctx
->data_directories
[IAT_IDX
].rva
)
619 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
));
623 name_rva
= translate_rva (ctx
, name_rva
);
624 g_assert (name_rva
!= INVALID_OFFSET
);
625 ptr
= ctx
->data
+ name_rva
;
627 if (memcmp ("mscoree.dll", ptr
, SIZE_OF_MSCOREE
)) {
628 char name
[SIZE_OF_MSCOREE
];
629 memcpy (name
, ptr
, SIZE_OF_MSCOREE
);
630 name
[SIZE_OF_MSCOREE
- 1] = 0;
631 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Import Table Name: '%s'", name
));
636 verify_hint_name_table (ctx
, ilt_rva
, "Import Lookup Table");
641 verify_hint_name_table (ctx
, iat_rva
, "Import Address Table");
645 verify_resources_table (VerifyContext
*ctx
)
647 DataDirectory it
= ctx
->data_directories
[RESOURCE_TABLE_IDX
];
649 guint16 named_entries
, id_entries
;
650 const char *ptr
, *root
, *end
;
656 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
));
658 offset
= it
.translated_offset
;
659 root
= ptr
= ctx
->data
+ offset
;
660 end
= root
+ it
.size
;
662 g_assert (offset
!= INVALID_OFFSET
);
664 named_entries
= read16 (ptr
+ 12);
665 id_entries
= read16 (ptr
+ 14);
667 if ((named_entries
+ id_entries
) * 8 + 16 > it
.size
)
668 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
));
670 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
671 if (named_entries || id_entries)
672 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
676 /*----------nothing from here on can use data_directory---*/
679 get_data_dir (VerifyContext
*ctx
, int idx
)
681 MonoCLIImageInfo
*iinfo
= ctx
->image
->image_info
;
682 MonoPEDirEntry
*entry
= &iinfo
->cli_header
.datadir
.pe_export_table
;
686 res
.rva
= entry
->rva
;
687 res
.size
= entry
->size
;
688 res
.translated_offset
= translate_rva (ctx
, res
.rva
);
693 verify_cli_header (VerifyContext
*ctx
)
695 DataDirectory it
= get_data_dir (ctx
, CLI_HEADER_IDX
);
701 ADD_ERROR (ctx
, g_strdup_printf ("CLI header missing"));
704 ADD_ERROR (ctx
, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it
.size
));
706 offset
= it
.translated_offset
;
707 ptr
= ctx
->data
+ offset
;
709 g_assert (offset
!= INVALID_OFFSET
);
711 if (read16 (ptr
) != 72)
712 ADD_ERROR (ctx
, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr
)));
714 if (!bounds_check_virtual_address (ctx
, read32 (ptr
+ 8), read32 (ptr
+ 12)))
715 ADD_ERROR (ctx
, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr
+ 8), read32 (ptr
+ 12)));
718 if (!read32 (ptr
+ 8) || !read32 (ptr
+ 12))
719 ADD_ERROR (ctx
, g_strdup_printf ("Missing medatata section in the CLI header"));
721 if ((read32 (ptr
+ 16) & ~0x0001000B) != 0)
722 ADD_ERROR (ctx
, g_strdup_printf ("Invalid CLI header flags"));
725 for (i
= 0; i
< 6; ++i
) {
726 guint32 rva
= read32 (ptr
);
727 guint32 size
= read32 (ptr
+ 4);
729 if (rva
!= 0 && !bounds_check_virtual_address (ctx
, rva
, size
))
730 ADD_ERROR (ctx
, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i
, rva
, size
));
735 ADD_ERROR (ctx
, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i
));
740 pad4 (guint32 offset
)
742 if (offset
& 0x3) //pad to the next 4 byte boundary
743 offset
= (offset
& ~0x3) + 4;
748 verify_metadata_header (VerifyContext
*ctx
)
751 DataDirectory it
= get_data_dir (ctx
, CLI_HEADER_IDX
);
752 guint32 offset
, section_count
;
755 offset
= it
.translated_offset
;
756 ptr
= ctx
->data
+ offset
;
757 g_assert (offset
!= INVALID_OFFSET
);
759 //build a directory entry for the metadata root
761 it
.rva
= read32 (ptr
);
763 it
.size
= read32 (ptr
);
764 it
.translated_offset
= offset
= translate_rva (ctx
, it
.rva
);
766 ptr
= ctx
->data
+ offset
;
767 g_assert (offset
!= INVALID_OFFSET
);
770 ADD_ERROR (ctx
, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it
.size
));
772 if (read32 (ptr
) != 0x424A5342)
773 ADD_ERROR (ctx
, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr
)));
775 offset
= pad4 (offset
+ 16 + read32 (ptr
+ 12));
777 if (!bounds_check_datadir (&it
, offset
, 4))
778 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
));
780 ptr
= ctx
->data
+ offset
; //move to streams header
782 section_count
= read16 (ptr
+ 2);
783 if (section_count
< 3)
784 ADD_ERROR (ctx
, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob"));
789 for (i
= 0; i
< section_count
; ++i
) {
790 guint32 stream_off
, stream_size
;
791 int string_size
, stream_idx
;
793 if (!bounds_check_datadir (&it
, offset
, 8))
794 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
));
796 stream_off
= it
.translated_offset
+ read32 (ptr
);
797 stream_size
= read32 (ptr
+ 4);
799 if (!bounds_check_datadir (&it
, stream_off
, stream_size
))
800 ADD_ERROR (ctx
, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off
, stream_size
));
805 for (string_size
= 0; string_size
< 32; ++string_size
) {
806 if (!bounds_check_datadir (&it
, offset
++, 1))
807 ADD_ERROR (ctx
, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i
));
808 if (!ptr
[string_size
])
812 if (ptr
[string_size
])
813 ADD_ERROR (ctx
, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i
));
815 if (!strncmp ("#Strings", ptr
, 9))
816 stream_idx
= STRINGS_STREAM
;
817 else if (!strncmp ("#US", ptr
, 4))
818 stream_idx
= USER_STRINGS_STREAM
;
819 else if (!strncmp ("#Blob", ptr
, 6))
820 stream_idx
= BLOB_STREAM
;
821 else if (!strncmp ("#GUID", ptr
, 6))
822 stream_idx
= GUID_STREAM
;
823 else if (!strncmp ("#~", ptr
, 3))
824 stream_idx
= TILDE_STREAM
;
826 ADD_WARNING (ctx
, g_strdup_printf ("Metadata stream header %d invalid name %s", i
, ptr
));
827 offset
= pad4 (offset
);
828 ptr
= ctx
->data
+ offset
;
832 if (ctx
->metadata_streams
[stream_idx
].offset
!= 0)
833 ADD_ERROR (ctx
, g_strdup_printf ("Duplicated metadata stream header %s", ptr
));
835 ctx
->metadata_streams
[stream_idx
].offset
= stream_off
;
836 ctx
->metadata_streams
[stream_idx
].size
= stream_size
;
838 offset
= pad4 (offset
);
839 ptr
= ctx
->data
+ offset
;
842 if (!ctx
->metadata_streams
[TILDE_STREAM
].size
)
843 ADD_ERROR (ctx
, g_strdup_printf ("Metadata #~ stream missing"));
844 if (!ctx
->metadata_streams
[GUID_STREAM
].size
)
845 ADD_ERROR (ctx
, g_strdup_printf ("Metadata guid stream missing"));
846 if (!ctx
->metadata_streams
[BLOB_STREAM
].size
)
847 ADD_ERROR (ctx
, g_strdup_printf ("Metadata blob stream missing"));
852 verify_tables_schema (VerifyContext
*ctx
)
854 OffsetAndSize tables_area
= ctx
->metadata_streams
[TILDE_STREAM
];
855 unsigned offset
= tables_area
.offset
;
856 const char *ptr
= ctx
->data
+ offset
;
857 guint64 valid_tables
;
861 if (tables_area
.size
< 24)
862 ADD_ERROR (ctx
, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area
.size
));
864 if (ptr
[4] != 2 && ptr
[4] != 1)
865 ADD_ERROR (ctx
, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr
[4]));
867 ADD_ERROR (ctx
, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr
[5]));
869 if ((ptr
[6] & ~0x7) != 0)
870 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]));
872 valid_tables
= read64 (ptr
+ 8);
874 for (i
= 0; i
< 64; ++i
) {
875 if (!(valid_tables
& ((guint64
)1 << i
)))
878 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
879 Unused: 0x1E 0x1F 0x2D-0x3F
880 We don't care about the MS extensions.*/
881 if (i
== 0x3 || i
== 0x5 || i
== 0x7 || i
== 0x13 || i
== 0x16)
882 ADD_ERROR (ctx
, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i
));
883 if (i
== 0x1E || i
== 0x1F || i
>= 0x2D)
884 ADD_ERROR (ctx
, g_strdup_printf ("Invalid table %x", i
));
888 if (tables_area
.size
< 24 + count
* 4)
889 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));
892 for (i
= 0; i
< 64; ++i
) {
893 if (valid_tables
& ((guint64
)1 << i
)) {
894 guint32 row_count
= read32 (ptr
);
895 if (row_count
> (1 << 24) - 1)
896 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i
, row_count
));
902 /*----------nothing from here on can use data_directory or metadata_streams ---*/
905 get_col_offset (VerifyContext
*ctx
, int table
, int column
)
907 guint32 bitfield
= ctx
->image
->tables
[table
].size_bitfield
;
911 offset
+= mono_metadata_table_size (bitfield
, column
);
917 get_col_size (VerifyContext
*ctx
, int table
, int column
)
919 return mono_metadata_table_size (ctx
->image
->tables
[table
].size_bitfield
, column
);
923 get_metadata_stream (VerifyContext
*ctx
, MonoStreamHeader
*header
)
926 res
.offset
= header
->data
- ctx
->data
;
927 res
.size
= header
->size
;
933 is_valid_string_full (VerifyContext
*ctx
, guint32 offset
, gboolean allow_empty
)
935 OffsetAndSize strings
= get_metadata_stream (ctx
, &ctx
->image
->heap_strings
);
937 const char *data
= ctx
->data
+ strings
.offset
;
939 if (offset
>= strings
.size
)
941 if (data
+ offset
< data
) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing
944 if (!mono_utf8_validate_and_len_with_bounds (data
+ offset
, strings
.size
- offset
, &length
, NULL
))
946 return allow_empty
|| length
> 0;
950 is_valid_string (VerifyContext
*ctx
, guint32 offset
)
952 return is_valid_string_full (ctx
, offset
, TRUE
);
956 is_valid_non_empty_string (VerifyContext
*ctx
, guint32 offset
)
958 return is_valid_string_full (ctx
, offset
, FALSE
);
962 is_valid_guid (VerifyContext
*ctx
, guint32 offset
)
964 OffsetAndSize guids
= get_metadata_stream (ctx
, &ctx
->image
->heap_guid
);
965 return guids
.size
>= 8 && guids
.size
- 8 >= offset
;
969 get_coded_index_token (int token_kind
, guint32 coded_token
)
971 guint32 bits
= coded_index_desc
[token_kind
];
972 return coded_token
>> bits
;
976 get_coded_index_table (int kind
, guint32 coded_token
)
978 guint32 idx
, bits
= coded_index_desc
[kind
];
980 idx
= coded_token
& ((1 << bits
) - 1);
981 return coded_index_desc
[kind
+ idx
];
985 make_coded_token (int kind
, guint32 table
, guint32 table_idx
)
987 guint32 bits
= coded_index_desc
[kind
++];
988 guint32 tables
= coded_index_desc
[kind
++];
990 for (i
= 0; i
< tables
; ++i
) {
991 if (coded_index_desc
[kind
++] == table
)
992 return ((table_idx
+ 1) << bits
) | i
;
994 g_assert_not_reached ();
999 is_valid_coded_index (VerifyContext
*ctx
, int token_kind
, guint32 coded_token
)
1001 guint32 bits
= coded_index_desc
[token_kind
++];
1002 guint32 table_count
= coded_index_desc
[token_kind
++];
1003 guint32 table
= coded_token
& ((1 << bits
) - 1);
1004 guint32 token
= coded_token
>> bits
;
1006 if (table
>= table_count
)
1009 /*token_kind points to the first table idx*/
1010 table
= coded_index_desc
[token_kind
+ table
];
1012 if (table
== INVALID_TABLE
)
1014 return token
<= ctx
->image
->tables
[table
].rows
;
1021 MonoTableInfo
*table
;
1025 token_locator (const void *a
, const void *b
)
1027 RowLocator
*loc
= (RowLocator
*)a
;
1028 unsigned const char *row
= (unsigned const char *)b
;
1029 guint32 token
= loc
->col_size
== 2 ? read16 (row
+ loc
->col_offset
) : read32 (row
+ loc
->col_offset
);
1031 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token
, ((const char*)row
- loc
->table
->base
) / loc
->table
->row_size
) );
1032 return (int)loc
->token
- (int)token
;
1036 search_sorted_table (VerifyContext
*ctx
, int table
, int column
, guint32 coded_token
)
1038 MonoTableInfo
*tinfo
= &ctx
->image
->tables
[table
];
1040 const char *res
, *base
;
1041 locator
.token
= coded_token
;
1042 locator
.col_offset
= get_col_offset (ctx
, table
, column
);
1043 locator
.col_size
= get_col_size (ctx
, table
, column
);
1044 locator
.table
= tinfo
;
1048 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
) );
1049 res
= bsearch (&locator
, base
, tinfo
->rows
, tinfo
->row_size
, token_locator
);
1053 return (res
- base
) / tinfo
->row_size
;
1056 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1058 get_string_ptr (VerifyContext
*ctx
, guint offset
)
1060 return ctx
->image
->heap_strings
.data
+ offset
;
1063 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1065 string_cmp (VerifyContext
*ctx
, const char *str
, guint offset
)
1068 return strcmp (str
, "");
1070 return strcmp (str
, get_string_ptr (ctx
, offset
));
1074 mono_verifier_is_corlib (MonoImage
*image
)
1076 gboolean trusted_location
= (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR
) ?
1077 TRUE
: mono_security_core_clr_is_platform_image (image
);
1079 return trusted_location
&& image
->module_name
&& !strcmp ("mscorlib.dll", image
->module_name
);
1083 typedef_is_system_object (VerifyContext
*ctx
, guint32
*data
)
1085 return mono_verifier_is_corlib (ctx
->image
) && !string_cmp (ctx
, "System", data
[MONO_TYPEDEF_NAMESPACE
]) && !string_cmp (ctx
, "Object", data
[MONO_TYPEDEF_NAME
]);
1089 decode_value (const char *_ptr
, unsigned available
, unsigned *value
, unsigned *size
)
1092 const unsigned char *ptr
= (const unsigned char *)_ptr
;
1100 if ((b
& 0x80) == 0) {
1103 } else if ((b
& 0x40) == 0) {
1107 *value
= ((b
& 0x3f) << 8 | ptr
[1]);
1112 *value
= ((b
& 0x1f) << 24) |
1122 decode_signature_header (VerifyContext
*ctx
, guint32 offset
, guint32
*size
, const char **first_byte
)
1124 MonoStreamHeader blob
= ctx
->image
->heap_blob
;
1125 guint32 value
, enc_size
;
1127 if (offset
>= blob
.size
)
1130 if (!decode_value (blob
.data
+ offset
, blob
.size
- offset
, &value
, &enc_size
))
1133 if (CHECK_ADD4_OVERFLOW_UN (offset
, enc_size
))
1138 if (ADD_IS_GREATER_OR_OVF (offset
, value
, blob
.size
))
1142 *first_byte
= blob
.data
+ offset
;
1147 safe_read (const char **_ptr
, const char *limit
, unsigned *dest
, int size
)
1149 const char *ptr
= *_ptr
;
1150 if (ptr
+ size
> limit
)
1154 *dest
= *((guint8
*)ptr
);
1158 *dest
= read16 (ptr
);
1162 *dest
= read32 (ptr
);
1171 safe_read_compressed_int (const char **_ptr
, const char *limit
, unsigned *dest
)
1174 const char *ptr
= *_ptr
;
1175 gboolean res
= decode_value (ptr
, limit
- ptr
, dest
, &size
);
1180 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1181 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1182 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1183 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1186 parse_type (VerifyContext
*ctx
, const char **_ptr
, const char *end
);
1189 parse_method_signature (VerifyContext
*ctx
, const char **_ptr
, const char *end
, gboolean allow_sentinel
, gboolean allow_unmanaged
);
1192 parse_custom_mods (VerifyContext
*ctx
, const char **_ptr
, const char *end
)
1194 const char *ptr
= *_ptr
;
1199 if (!safe_read8 (type
, ptr
, end
))
1200 FAIL (ctx
, g_strdup ("CustomMod: Not enough room for the type"));
1202 if (type
!= MONO_TYPE_CMOD_REQD
&& type
!= MONO_TYPE_CMOD_OPT
) {
1207 if (!safe_read_cint (token
, ptr
, end
))
1208 FAIL (ctx
, g_strdup ("CustomMod: Not enough room for the token"));
1210 if (!is_valid_coded_index (ctx
, TYPEDEF_OR_REF_DESC
, token
))
1211 FAIL (ctx
, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token
));
1219 parse_array_shape (VerifyContext
*ctx
, const char **_ptr
, const char *end
)
1221 const char *ptr
= *_ptr
;
1223 unsigned size
, num
, i
;
1225 if (!safe_read8 (val
, ptr
, end
))
1226 FAIL (ctx
, g_strdup ("ArrayShape: Not enough room for Rank"));
1229 FAIL (ctx
, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1231 if (!safe_read_cint (size
, ptr
, end
))
1232 FAIL (ctx
, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1234 for (i
= 0; i
< size
; ++i
) {
1235 if (!safe_read_cint (num
, ptr
, end
))
1236 FAIL (ctx
, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i
+ 1));
1239 if (!safe_read_cint (size
, ptr
, end
))
1240 FAIL (ctx
, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1242 for (i
= 0; i
< size
; ++i
) {
1243 if (!safe_read_cint (num
, ptr
, end
))
1244 FAIL (ctx
, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i
+ 1));
1252 parse_generic_inst (VerifyContext
*ctx
, const char **_ptr
, const char *end
)
1254 const char *ptr
= *_ptr
;
1256 unsigned count
, token
, i
;
1258 if (!safe_read8 (type
, ptr
, end
))
1259 FAIL (ctx
, g_strdup ("GenericInst: Not enough room for kind"));
1261 if (type
!= MONO_TYPE_CLASS
&& type
!= MONO_TYPE_VALUETYPE
)
1262 FAIL (ctx
, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type
));
1264 if (!safe_read_cint (token
, ptr
, end
))
1265 FAIL (ctx
, g_strdup ("GenericInst: Not enough room for type token"));
1267 if (!is_valid_coded_index (ctx
, TYPEDEF_OR_REF_DESC
, token
))
1268 FAIL (ctx
, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token
));
1271 if (mono_metadata_token_index (ctx
->token
) == get_coded_index_token (TYPEDEF_OR_REF_DESC
, token
) &&
1272 mono_metadata_token_table (ctx
->token
) == get_coded_index_table (TYPEDEF_OR_REF_DESC
, token
))
1273 FAIL (ctx
, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx
->token
));
1276 if (!safe_read_cint (count
, ptr
, end
))
1277 FAIL (ctx
, g_strdup ("GenericInst: Not enough room for argument count"));
1280 FAIL (ctx
, g_strdup ("GenericInst: Zero arguments generic instance"));
1282 for (i
= 0; i
< count
; ++i
) {
1283 if (!parse_type (ctx
, &ptr
, end
))
1284 FAIL (ctx
, g_strdup_printf ("GenericInst: invalid generic argument %d", i
+ 1));
1291 parse_type (VerifyContext
*ctx
, const char **_ptr
, const char *end
)
1293 const char *ptr
= *_ptr
;
1297 if (!safe_read8 (type
, ptr
, end
))
1298 FAIL (ctx
, g_strdup ("Type: Not enough room for the type"));
1300 if (!((type
>= MONO_TYPE_BOOLEAN
&& type
<= MONO_TYPE_PTR
) ||
1301 (type
>= MONO_TYPE_VALUETYPE
&& type
<= MONO_TYPE_GENERICINST
) ||
1302 (type
>= MONO_TYPE_I
&& type
<= MONO_TYPE_U
) ||
1303 (type
>= MONO_TYPE_FNPTR
&& type
<= MONO_TYPE_MVAR
)))
1304 FAIL (ctx
, g_strdup_printf ("Type: Invalid type kind %x\n", type
));
1308 if (!parse_custom_mods (ctx
, &ptr
, end
))
1309 FAIL (ctx
, g_strdup ("Type: Failed to parse pointer custom attr"));
1311 if (!safe_read8 (type
, ptr
, end
))
1312 FAIL (ctx
, g_strdup ("Type: Not enough room to parse the pointer type"));
1314 if (type
!= MONO_TYPE_VOID
) {
1316 if (!parse_type (ctx
, &ptr
, end
))
1317 FAIL (ctx
, g_strdup ("Type: Could not parse pointer type"));
1321 case MONO_TYPE_VALUETYPE
:
1322 case MONO_TYPE_CLASS
:
1323 if (!safe_read_cint (token
, ptr
, end
))
1324 FAIL (ctx
, g_strdup ("Type: Not enough room for the type token"));
1326 if (!is_valid_coded_index (ctx
, TYPEDEF_OR_REF_DESC
, token
))
1327 FAIL (ctx
, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token
));
1329 if (mono_metadata_token_index (ctx
->token
) == get_coded_index_token (TYPEDEF_OR_REF_DESC
, token
) &&
1330 mono_metadata_token_table (ctx
->token
) == get_coded_index_table (TYPEDEF_OR_REF_DESC
, token
))
1331 FAIL (ctx
, g_strdup_printf ("Type: Recurside type specification (%x). A type signature can't reference itself", ctx
->token
));
1336 case MONO_TYPE_MVAR
:
1337 if (!safe_read_cint (token
, ptr
, end
))
1338 FAIL (ctx
, g_strdup ("Type: Not enough room for to decode generic argument number"));
1341 case MONO_TYPE_ARRAY
:
1342 if (!parse_type (ctx
, &ptr
, end
))
1343 FAIL (ctx
, g_strdup ("Type: Could not parse array type"));
1344 if (!parse_array_shape (ctx
, &ptr
, end
))
1345 FAIL (ctx
, g_strdup ("Type: Could not parse array shape"));
1348 case MONO_TYPE_GENERICINST
:
1349 if (!parse_generic_inst (ctx
, &ptr
, end
))
1350 FAIL (ctx
, g_strdup ("Type: Could not parse generic inst"));
1353 case MONO_TYPE_FNPTR
:
1354 if (!parse_method_signature (ctx
, &ptr
, end
, TRUE
, TRUE
))
1355 FAIL (ctx
, g_strdup ("Type: Could not parse method pointer signature"));
1358 case MONO_TYPE_SZARRAY
:
1359 if (!parse_custom_mods (ctx
, &ptr
, end
))
1360 FAIL (ctx
, g_strdup ("Type: Failed to parse array element custom attr"));
1361 if (!parse_type (ctx
, &ptr
, end
))
1362 FAIL (ctx
, g_strdup ("Type: Could not parse array type"));
1370 parse_return_type (VerifyContext
*ctx
, const char **_ptr
, const char *end
)
1375 if (!parse_custom_mods (ctx
, _ptr
, end
))
1379 if (!safe_read8 (type
, ptr
, end
))
1380 FAIL (ctx
, g_strdup ("ReturnType: Not enough room for the type"));
1382 if (type
== MONO_TYPE_VOID
|| type
== MONO_TYPE_TYPEDBYREF
) {
1387 //it's a byref, update the cursor ptr
1388 if (type
== MONO_TYPE_BYREF
)
1391 return parse_type (ctx
, _ptr
, end
);
1395 parse_param (VerifyContext
*ctx
, const char **_ptr
, const char *end
)
1400 if (!parse_custom_mods (ctx
, _ptr
, end
))
1404 if (!safe_read8 (type
, ptr
, end
))
1405 FAIL (ctx
, g_strdup ("Param: Not enough room for the type"));
1407 if (type
== MONO_TYPE_TYPEDBYREF
) {
1412 //it's a byref, update the cursor ptr
1413 if (type
== MONO_TYPE_BYREF
)
1416 return parse_type (ctx
, _ptr
, end
);
1420 parse_method_signature (VerifyContext
*ctx
, const char **_ptr
, const char *end
, gboolean allow_sentinel
, gboolean allow_unmanaged
)
1423 unsigned param_count
= 0, gparam_count
= 0, type
= 0, i
;
1424 const char *ptr
= *_ptr
;
1425 gboolean saw_sentinel
= FALSE
;
1427 if (!safe_read8 (cconv
, ptr
, end
))
1428 FAIL (ctx
, g_strdup ("MethodSig: Not enough room for the call conv"));
1431 FAIL (ctx
, g_strdup ("MethodSig: CallConv has 0x80 set"));
1433 if (allow_unmanaged
) {
1434 if ((cconv
& 0x0F) > MONO_CALL_VARARG
)
1435 FAIL (ctx
, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv
& 0x0F));
1436 } else if ((cconv
& 0x0F) != MONO_CALL_DEFAULT
&& (cconv
& 0x0F) != MONO_CALL_VARARG
)
1437 FAIL (ctx
, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv
& 0x0F));
1439 if ((cconv
& 0x10) && !safe_read_cint (gparam_count
, ptr
, end
))
1440 FAIL (ctx
, g_strdup ("MethodSig: Not enough room for the generic param count"));
1442 if ((cconv
& 0x10) && gparam_count
== 0)
1443 FAIL (ctx
, g_strdup ("MethodSig: Signature with generics but zero arity"));
1445 if (allow_unmanaged
&& (cconv
& 0x10))
1446 FAIL (ctx
, g_strdup ("MethodSig: Standalone signature with generic params"));
1448 if (!safe_read_cint (param_count
, ptr
, end
))
1449 FAIL (ctx
, g_strdup ("MethodSig: Not enough room for the param count"));
1451 if (!parse_return_type (ctx
, &ptr
, end
))
1452 FAIL (ctx
, g_strdup ("MethodSig: Error parsing return type"));
1454 for (i
= 0; i
< param_count
; ++i
) {
1455 if (allow_sentinel
) {
1456 if (!safe_read8 (type
, ptr
, end
))
1457 FAIL (ctx
, g_strdup_printf ("MethodSig: Not enough room for param %d type", i
));
1459 if (type
== MONO_TYPE_SENTINEL
) {
1460 if ((cconv
& 0x0F) != MONO_CALL_VARARG
)
1461 FAIL (ctx
, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1464 FAIL (ctx
, g_strdup ("MethodSig: More than one sentinel type"));
1466 saw_sentinel
= TRUE
;
1472 if (!parse_param (ctx
, &ptr
, end
))
1473 FAIL (ctx
, g_strdup_printf ("MethodSig: Error parsing arg %d", i
));
1481 parse_property_signature (VerifyContext
*ctx
, const char **_ptr
, const char *end
)
1484 unsigned param_count
= 0, i
;
1485 const char *ptr
= *_ptr
;
1487 if (!safe_read8 (sig
, ptr
, end
))
1488 FAIL (ctx
, g_strdup ("PropertySig: Not enough room for signature"));
1490 if (sig
!= 0x08 && sig
!= 0x28)
1491 FAIL (ctx
, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig
));
1493 if (!safe_read_cint (param_count
, ptr
, end
))
1494 FAIL (ctx
, g_strdup ("PropertySig: Not enough room for the param count"));
1496 if (!parse_custom_mods (ctx
, &ptr
, end
))
1499 if (!parse_type (ctx
, &ptr
, end
))
1500 FAIL (ctx
, g_strdup ("PropertySig: Could not parse property type"));
1502 for (i
= 0; i
< param_count
; ++i
) {
1503 if (!parse_type (ctx
, &ptr
, end
))
1504 FAIL (ctx
, g_strdup_printf ("PropertySig: Error parsing arg %d", i
));
1512 parse_field (VerifyContext
*ctx
, const char **_ptr
, const char *end
)
1514 const char *ptr
= *_ptr
;
1515 unsigned signature
= 0;
1517 if (!safe_read8 (signature
, ptr
, end
))
1518 FAIL (ctx
, g_strdup ("Field: Not enough room for field signature"));
1520 if (signature
!= 0x06)
1521 FAIL (ctx
, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature
));
1523 if (!parse_custom_mods (ctx
, &ptr
, end
))
1526 if (safe_read8 (signature
, ptr
, end
)) {
1527 if (signature
!= MONO_TYPE_BYREF
)
1532 return parse_type (ctx
, _ptr
, end
);
1536 parse_locals_signature (VerifyContext
*ctx
, const char **_ptr
, const char *end
)
1539 unsigned locals_count
= 0, i
;
1540 const char *ptr
= *_ptr
;
1542 if (!safe_read8 (sig
, ptr
, end
))
1543 FAIL (ctx
, g_strdup ("LocalsSig: Not enough room for signature"));
1546 FAIL (ctx
, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig
));
1548 if (!safe_read_cint (locals_count
, ptr
, end
))
1549 FAIL (ctx
, g_strdup ("LocalsSig: Not enough room for the param count"));
1551 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1552 if (locals_count == 0)
1553 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1556 for (i
= 0; i
< locals_count
; ++i
) {
1557 if (!safe_read8 (sig
, ptr
, end
))
1558 FAIL (ctx
, g_strdup ("LocalsSig: Not enough room for type"));
1560 while (sig
== MONO_TYPE_CMOD_REQD
|| sig
== MONO_TYPE_CMOD_OPT
|| sig
== MONO_TYPE_PINNED
) {
1561 if (sig
!= MONO_TYPE_PINNED
&& !parse_custom_mods (ctx
, &ptr
, end
))
1562 FAIL (ctx
, g_strdup_printf ("LocalsSig: Error parsing local %d", i
));
1563 if (!safe_read8 (sig
, ptr
, end
))
1564 FAIL (ctx
, g_strdup ("LocalsSig: Not enough room for type"));
1567 if (sig
== MONO_TYPE_BYREF
) {
1568 if (!safe_read8 (sig
, ptr
, end
))
1569 FAIL (ctx
, g_strdup_printf ("Type: Not enough room for byref type for local %d", i
));
1570 if (sig
== MONO_TYPE_TYPEDBYREF
)
1571 FAIL (ctx
, g_strdup_printf ("Type: Invalid type typedref& for local %d", i
));
1574 if (sig
== MONO_TYPE_TYPEDBYREF
)
1579 if (!parse_type (ctx
, &ptr
, end
))
1580 FAIL (ctx
, g_strdup_printf ("LocalsSig: Error parsing local %d", i
));
1588 is_valid_field_signature (VerifyContext
*ctx
, guint32 offset
)
1591 unsigned signature
= 0;
1592 const char *ptr
= NULL
, *end
;
1594 if (!decode_signature_header (ctx
, offset
, &size
, &ptr
))
1595 FAIL (ctx
, g_strdup ("FieldSig: Could not decode signature header"));
1598 if (!safe_read8 (signature
, ptr
, end
))
1599 FAIL (ctx
, g_strdup ("FieldSig: Not enough room for the signature"));
1602 FAIL (ctx
, g_strdup_printf ("FieldSig: Invalid signature %x", signature
));
1605 return parse_field (ctx
, &ptr
, end
);
1609 is_valid_method_signature (VerifyContext
*ctx
, guint32 offset
)
1612 const char *ptr
= NULL
, *end
;
1614 if (!decode_signature_header (ctx
, offset
, &size
, &ptr
))
1615 FAIL (ctx
, g_strdup ("MethodSig: Could not decode signature header"));
1618 return parse_method_signature (ctx
, &ptr
, end
, FALSE
, FALSE
);
1622 is_valid_method_or_field_signature (VerifyContext
*ctx
, guint32 offset
)
1625 unsigned signature
= 0;
1626 const char *ptr
= NULL
, *end
;
1628 if (!decode_signature_header (ctx
, offset
, &size
, &ptr
))
1629 FAIL (ctx
, g_strdup ("MemberRefSig: Could not decode signature header"));
1632 if (!safe_read8 (signature
, ptr
, end
))
1633 FAIL (ctx
, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1636 if (signature
== 0x06)
1637 return parse_field (ctx
, &ptr
, end
);
1639 return parse_method_signature (ctx
, &ptr
, end
, TRUE
, FALSE
);
1643 is_valid_cattr_blob (VerifyContext
*ctx
, guint32 offset
)
1646 unsigned prolog
= 0;
1647 const char *ptr
= NULL
, *end
;
1652 if (!decode_signature_header (ctx
, offset
, &size
, &ptr
))
1653 FAIL (ctx
, g_strdup ("CustomAttribute: Could not decode signature header"));
1656 if (!safe_read16 (prolog
, ptr
, end
))
1657 FAIL (ctx
, g_strdup ("CustomAttribute: Not enough room for prolog"));
1660 FAIL (ctx
, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog
));
1666 is_valid_cattr_type (MonoType
*type
)
1670 if (type
->type
== MONO_TYPE_OBJECT
|| (type
->type
>= MONO_TYPE_BOOLEAN
&& type
->type
<= MONO_TYPE_STRING
))
1673 if (type
->type
== MONO_TYPE_VALUETYPE
) {
1674 klass
= mono_class_from_mono_type (type
);
1675 return klass
&& klass
->enumtype
;
1678 if (type
->type
== MONO_TYPE_CLASS
)
1679 return mono_class_from_mono_type (type
) == mono_defaults
.systemtype_class
;
1685 is_valid_ser_string_full (VerifyContext
*ctx
, const char **str_start
, guint32
*str_len
, const char **_ptr
, const char *end
)
1688 const char *ptr
= *_ptr
;
1694 FAIL (ctx
, g_strdup ("CustomAttribute: Not enough room for string size"));
1697 if (*ptr
== (char)0xFF) {
1702 if (!safe_read_cint (size
, ptr
, end
))
1703 FAIL (ctx
, g_strdup ("CustomAttribute: Not enough room for string size"));
1705 if (ADDP_IS_GREATER_OR_OVF (ptr
, size
, end
))
1706 FAIL (ctx
, g_strdup ("CustomAttribute: Not enough room for string"));
1716 is_valid_ser_string (VerifyContext
*ctx
, const char **_ptr
, const char *end
)
1718 const char *dummy_str
;
1720 return is_valid_ser_string_full (ctx
, &dummy_str
, &dummy_int
, _ptr
, end
);
1724 get_enum_by_encoded_name (VerifyContext
*ctx
, const char **_ptr
, const char *end
)
1728 const char *str_start
= NULL
;
1729 const char *ptr
= *_ptr
;
1731 guint32 str_len
= 0;
1733 if (!is_valid_ser_string_full (ctx
, &str_start
, &str_len
, &ptr
, end
))
1736 /*NULL or empty string*/
1737 if (str_start
== NULL
|| str_len
== 0) {
1738 ADD_ERROR_NO_RETURN (ctx
, g_strdup ("CustomAttribute: Null or empty enum name"));
1742 enum_name
= g_memdup (str_start
, str_len
+ 1);
1743 enum_name
[str_len
] = 0;
1744 type
= mono_reflection_type_from_name (enum_name
, ctx
->image
);
1746 ADD_ERROR_NO_RETURN (ctx
, g_strdup_printf ("CustomAttribute: Invalid enum class %s", enum_name
));
1752 klass
= mono_class_from_mono_type (type
);
1753 if (!klass
|| !klass
->enumtype
) {
1754 ADD_ERROR_NO_RETURN (ctx
, g_strdup_printf ("CustomAttribute:Class %s::%s is not an enum", klass
->name_space
, klass
->name
));
1763 is_valid_fixed_param (VerifyContext
*ctx
, MonoType
*mono_type
, const char **_ptr
, const char *end
)
1766 const char *ptr
= *_ptr
;
1768 guint32 element_count
, i
;
1771 klass
= mono_type
->data
.klass
;
1772 type
= mono_type
->type
;
1776 case MONO_TYPE_BOOLEAN
:
1783 case MONO_TYPE_CHAR
:
1797 case MONO_TYPE_STRING
:
1799 return is_valid_ser_string (ctx
, _ptr
, end
);
1801 case MONO_TYPE_OBJECT
: {
1802 unsigned sub_type
= 0;
1803 if (!safe_read8 (sub_type
, ptr
, end
))
1804 FAIL (ctx
, g_strdup ("CustomAttribute: Not enough room for array type"));
1806 if (sub_type
>= MONO_TYPE_BOOLEAN
&& sub_type
<= MONO_TYPE_STRING
) {
1810 if (sub_type
== MONO_TYPE_ENUM
) {
1811 klass
= get_enum_by_encoded_name (ctx
, &ptr
, end
);
1815 klass
= klass
->element_class
;
1816 type
= klass
->byval_arg
.type
;
1819 if (sub_type
== 0x50) { /*Type*/
1821 return is_valid_ser_string (ctx
, _ptr
, end
);
1823 if (sub_type
== MONO_TYPE_SZARRAY
) {
1824 MonoType simple_type
= {{0}};
1826 if (!safe_read8 (etype
, ptr
, end
))
1827 FAIL (ctx
, g_strdup ("CustomAttribute: Not enough room for array element type"));
1829 if (etype
== MONO_TYPE_ENUM
) {
1830 klass
= get_enum_by_encoded_name (ctx
, &ptr
, end
);
1833 } else if ((etype
>= MONO_TYPE_BOOLEAN
&& etype
<= MONO_TYPE_STRING
) || etype
== 0x51) {
1834 simple_type
.type
= etype
== 0x51 ? MONO_TYPE_OBJECT
: etype
;
1835 klass
= mono_class_from_mono_type (&simple_type
);
1837 FAIL (ctx
, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype
));
1839 type
= MONO_TYPE_SZARRAY
;
1842 FAIL (ctx
, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type
));
1846 case MONO_TYPE_CLASS
:
1847 if (klass
!= mono_defaults
.systemtype_class
)
1848 FAIL (ctx
, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass
->name_space
, klass
->name
));
1850 return is_valid_ser_string (ctx
, _ptr
, end
);
1852 case MONO_TYPE_VALUETYPE
:
1853 if (!klass
|| !klass
->enumtype
)
1854 FAIL (ctx
, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass
->name_space
, klass
->name
));
1856 klass
= klass
->element_class
;
1857 type
= klass
->byval_arg
.type
;
1860 case MONO_TYPE_SZARRAY
:
1861 mono_type
= &klass
->byval_arg
;
1862 if (!is_valid_cattr_type (mono_type
))
1863 FAIL (ctx
, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass
->name_space
, klass
->name
));
1864 if (!safe_read32 (element_count
, ptr
, end
))
1865 FAIL (ctx
, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass
->name_space
, klass
->name
));
1866 if (element_count
== 0xFFFFFFFFu
) {
1870 for (i
= 0; i
< element_count
; ++i
) {
1871 if (!is_valid_fixed_param (ctx
, mono_type
, &ptr
, end
))
1877 FAIL (ctx
, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type
));
1880 if (ADDP_IS_GREATER_OR_OVF (ptr
, elem_size
, end
))
1881 FAIL (ctx
, g_strdup ("CustomAttribute: Not enough space for element"));
1882 *_ptr
= ptr
+ elem_size
;
1887 is_valid_cattr_content (VerifyContext
*ctx
, MonoMethod
*ctor
, const char *ptr
, guint32 size
)
1890 unsigned prolog
= 0;
1892 MonoMethodSignature
*sig
;
1897 FAIL (ctx
, g_strdup ("CustomAttribute: Invalid constructor"));
1899 sig
= mono_method_signature_checked (ctor
, &error
);
1900 if (!mono_error_ok (&error
)) {
1901 ADD_ERROR_NO_RETURN (ctx
, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error
)));
1902 mono_error_cleanup (&error
);
1906 if (sig
->sentinelpos
!= -1 || sig
->call_convention
== MONO_CALL_VARARG
)
1907 FAIL (ctx
, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1911 if (!safe_read16 (prolog
, ptr
, end
))
1912 FAIL (ctx
, g_strdup ("CustomAttribute: Not enough room for prolog"));
1915 FAIL (ctx
, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog
));
1917 args
= sig
->param_count
;
1918 for (i
= 0; i
< args
; ++i
) {
1919 MonoType
*arg_type
= sig
->params
[i
];
1920 if (!is_valid_fixed_param (ctx
, arg_type
, &ptr
, end
))
1924 if (!safe_read16 (num_named
, ptr
, end
))
1925 FAIL (ctx
, g_strdup ("CustomAttribute: Not enough space for num_named field"));
1927 for (i
= 0; i
< num_named
; ++i
) {
1928 MonoType
*type
, simple_type
= {{0}};
1931 if (!safe_read8 (kind
, ptr
, end
))
1932 FAIL (ctx
, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i
));
1933 if (kind
!= 0x53 && kind
!= 0x54)
1934 FAIL (ctx
, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i
, kind
));
1935 if (!safe_read8 (kind
, ptr
, end
))
1936 FAIL (ctx
, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i
));
1938 if (kind
>= MONO_TYPE_BOOLEAN
&& kind
<= MONO_TYPE_STRING
) {
1939 simple_type
.type
= kind
;
1940 type
= &simple_type
;
1941 } else if (kind
== MONO_TYPE_ENUM
) {
1942 MonoClass
*klass
= get_enum_by_encoded_name (ctx
, &ptr
, end
);
1945 type
= &klass
->byval_arg
;
1946 } else if (kind
== 0x50) {
1947 type
= &mono_defaults
.systemtype_class
->byval_arg
;
1948 } else if (kind
== 0x51) {
1949 type
= &mono_defaults
.object_class
->byval_arg
;
1950 } else if (kind
== MONO_TYPE_SZARRAY
) {
1953 if (!safe_read8 (etype
, ptr
, end
))
1954 FAIL (ctx
, g_strdup ("CustomAttribute: Not enough room for array element type"));
1956 if (etype
== MONO_TYPE_ENUM
) {
1957 klass
= get_enum_by_encoded_name (ctx
, &ptr
, end
);
1960 } else if ((etype
>= MONO_TYPE_BOOLEAN
&& etype
<= MONO_TYPE_STRING
) || etype
== 0x51) {
1961 simple_type
.type
= etype
== 0x51 ? MONO_TYPE_OBJECT
: etype
;
1962 klass
= mono_class_from_mono_type (&simple_type
);
1964 FAIL (ctx
, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype
));
1966 type
= &mono_array_class_get (klass
, 1)->byval_arg
;
1968 FAIL (ctx
, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind
));
1971 if (!is_valid_ser_string (ctx
, &ptr
, end
))
1974 if (!is_valid_fixed_param (ctx
, type
, &ptr
, end
))
1983 is_valid_marshal_spec (VerifyContext
*ctx
, guint32 offset
)
1985 OffsetAndSize blob
= get_metadata_stream (ctx
, &ctx
->image
->heap_blob
);
1986 //TODO do proper verification
1987 return blob
.size
>= 1 && blob
.size
- 1 >= offset
;
1991 is_valid_permission_set (VerifyContext
*ctx
, guint32 offset
)
1993 OffsetAndSize blob
= get_metadata_stream (ctx
, &ctx
->image
->heap_blob
);
1994 //TODO do proper verification
1995 return blob
.size
>= 1 && blob
.size
- 1 >= offset
;
1999 is_valid_standalonesig_blob (VerifyContext
*ctx
, guint32 offset
)
2002 unsigned signature
= 0;
2003 const char *ptr
= NULL
, *end
;
2005 if (!decode_signature_header (ctx
, offset
, &size
, &ptr
))
2006 FAIL (ctx
, g_strdup ("StandAloneSig: Could not decode signature header"));
2009 if (!safe_read8 (signature
, ptr
, end
))
2010 FAIL (ctx
, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2013 if (signature
== 0x07)
2014 return parse_locals_signature (ctx
, &ptr
, end
);
2016 /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
2017 if (signature
== 0x06)
2018 return parse_field (ctx
, &ptr
, end
);
2020 return parse_method_signature (ctx
, &ptr
, end
, TRUE
, TRUE
);
2024 is_valid_property_sig_blob (VerifyContext
*ctx
, guint32 offset
)
2027 const char *ptr
= NULL
, *end
;
2029 if (!decode_signature_header (ctx
, offset
, &size
, &ptr
))
2030 FAIL (ctx
, g_strdup ("PropertySig: Could not decode signature header"));
2033 return parse_property_signature (ctx
, &ptr
, end
);
2037 is_valid_typespec_blob (VerifyContext
*ctx
, guint32 offset
)
2040 const char *ptr
= NULL
, *end
;
2043 if (!decode_signature_header (ctx
, offset
, &size
, &ptr
))
2044 FAIL (ctx
, g_strdup ("TypeSpec: Could not decode signature header"));
2047 if (!parse_custom_mods (ctx
, &ptr
, end
))
2050 if (!safe_read8 (type
, ptr
, end
))
2051 FAIL (ctx
, g_strdup ("TypeSpec: Not enough room for type"));
2053 if (type
== MONO_TYPE_BYREF
) {
2054 if (!safe_read8 (type
, ptr
, end
))
2055 FAIL (ctx
, g_strdup ("TypeSpec: Not enough room for byref type"));
2056 if (type
== MONO_TYPE_TYPEDBYREF
)
2057 FAIL (ctx
, g_strdup ("TypeSpec: Invalid type typedref&"));
2060 if (type
== MONO_TYPE_TYPEDBYREF
)
2064 return parse_type (ctx
, &ptr
, end
);
2068 is_valid_methodspec_blob (VerifyContext
*ctx
, guint32 offset
)
2071 const char *ptr
= NULL
, *end
;
2073 unsigned count
= 0, i
;
2075 if (!decode_signature_header (ctx
, offset
, &size
, &ptr
))
2076 FAIL (ctx
, g_strdup ("MethodSpec: Could not decode signature header"));
2079 if (!safe_read8 (type
, ptr
, end
))
2080 FAIL (ctx
, g_strdup ("MethodSpec: Not enough room for call convention"));
2083 FAIL (ctx
, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type
));
2085 if (!safe_read_cint (count
, ptr
, end
))
2086 FAIL (ctx
, g_strdup ("MethodSpec: Not enough room for parameter count"));
2089 FAIL (ctx
, g_strdup ("MethodSpec: Zero generic argument count"));
2091 for (i
= 0; i
< count
; ++i
) {
2092 if (!parse_type (ctx
, &ptr
, end
))
2093 FAIL (ctx
, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i
+ 1));
2099 is_valid_blob_object (VerifyContext
*ctx
, guint32 offset
, guint32 minsize
)
2101 OffsetAndSize blob
= get_metadata_stream (ctx
, &ctx
->image
->heap_blob
);
2102 guint32 entry_size
, bytes
;
2104 if (blob
.size
< offset
)
2107 if (!decode_value (ctx
->data
+ offset
+ blob
.offset
, blob
.size
- blob
.offset
, &entry_size
, &bytes
))
2110 if (entry_size
< minsize
)
2113 if (CHECK_ADD4_OVERFLOW_UN (entry_size
, bytes
))
2115 entry_size
+= bytes
;
2117 return !ADD_IS_GREATER_OR_OVF (offset
, entry_size
, blob
.size
);
2121 is_valid_constant (VerifyContext
*ctx
, guint32 type
, guint32 offset
)
2123 OffsetAndSize blob
= get_metadata_stream (ctx
, &ctx
->image
->heap_blob
);
2124 guint32 size
, entry_size
, bytes
;
2126 if (blob
.size
< offset
)
2127 FAIL (ctx
, g_strdup ("ContantValue: invalid offset"));
2129 if (!decode_value (ctx
->data
+ offset
+ blob
.offset
, blob
.size
- blob
.offset
, &entry_size
, &bytes
))
2130 FAIL (ctx
, g_strdup ("ContantValue: not enough space to decode size"));
2132 if (type
== MONO_TYPE_STRING
) {
2133 //String is encoded as: compressed_int:len len *bytes
2136 if (ADD_IS_GREATER_OR_OVF (offset
, entry_size
, blob
.size
))
2137 FAIL (ctx
, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size
* 2, blob
.size
- offset
));
2143 case MONO_TYPE_BOOLEAN
:
2148 case MONO_TYPE_CHAR
:
2156 case MONO_TYPE_CLASS
:
2166 g_assert_not_reached ();
2169 if (size
!= entry_size
)
2170 FAIL (ctx
, g_strdup_printf ("ContantValue: Expected size %d but got %d", size
, entry_size
));
2174 if (ADD_IS_GREATER_OR_OVF (offset
, size
, blob
.size
))
2175 FAIL (ctx
, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size
, blob
.size
- offset
));
2177 if (type
== MONO_TYPE_CLASS
&& read32 (ctx
->data
+ blob
.offset
+ offset
))
2178 FAIL (ctx
, g_strdup_printf ("ContantValue: Type is class but value is not null"));
2182 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
2183 //only 0x01, 0x40 and 0x80 are allowed
2184 #define SECTION_HEADER_INVALID_FLAGS 0x3E
2187 is_valid_method_header (VerifyContext
*ctx
, guint32 rva
)
2189 unsigned local_vars_tok
, code_size
, offset
= mono_cli_rva_image_map (ctx
->image
, rva
);
2190 unsigned header
= 0;
2191 unsigned fat_header
= 0, size
= 0, max_stack
;
2192 const char *ptr
= NULL
, *end
;
2194 if (offset
== INVALID_ADDRESS
)
2195 FAIL (ctx
, g_strdup ("MethodHeader: Invalid RVA"));
2197 ptr
= ctx
->data
+ offset
;
2198 end
= ctx
->data
+ ctx
->size
; /*no worries if it spawns multiple sections*/
2200 if (!safe_read8 (header
, ptr
, end
))
2201 FAIL (ctx
, g_strdup ("MethodHeader: Not enough room for header"));
2203 switch (header
& 0x3) {
2206 FAIL (ctx
, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header
& 0x3));
2209 if (ADDP_IS_GREATER_OR_OVF (ptr
, header
, end
))
2210 FAIL (ctx
, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header
, (int)(end
- ptr
)));
2215 if (!safe_read16 (fat_header
, ptr
, end
))
2216 FAIL (ctx
, g_strdup ("MethodHeader: Not enough room for fat header"));
2218 size
= (fat_header
>> 12) & 0xF;
2220 FAIL (ctx
, g_strdup ("MethodHeader: header size must be 3"));
2222 if (!safe_read16 (max_stack
, ptr
, end
))
2223 FAIL (ctx
, g_strdup ("MethodHeader: Not enough room for max stack"));
2225 if (!safe_read32 (code_size
, ptr
, end
))
2226 FAIL (ctx
, g_strdup ("MethodHeader: Not enough room for code size"));
2228 if (!safe_read32 (local_vars_tok
, ptr
, end
))
2229 FAIL (ctx
, g_strdup ("MethodHeader: Not enough room for local vars tok"));
2231 if (local_vars_tok
) {
2232 if (((local_vars_tok
>> 24) & 0xFF) != 0x11)
2233 FAIL (ctx
, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok
>> 24) & 0xFF)));
2234 if ((local_vars_tok
& 0xFFFFFF) > ctx
->image
->tables
[MONO_TABLE_STANDALONESIG
].rows
)
2235 FAIL (ctx
, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok
& 0xFFFFFF));
2238 if (fat_header
& FAT_HEADER_INVALID_FLAGS
)
2239 FAIL (ctx
, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header
& FAT_HEADER_INVALID_FLAGS
));
2241 if (ADDP_IS_GREATER_OR_OVF (ptr
, code_size
, end
))
2242 FAIL (ctx
, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size
));
2244 if (!(fat_header
& 0x08))
2250 unsigned section_header
= 0, section_size
= 0;
2253 ptr
= dword_align (ptr
);
2254 if (!safe_read32 (section_header
, ptr
, end
))
2255 FAIL (ctx
, g_strdup ("MethodHeader: Not enough room for data section header"));
2257 if (section_header
& SECTION_HEADER_INVALID_FLAGS
)
2258 FAIL (ctx
, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header
& SECTION_HEADER_INVALID_FLAGS
));
2260 is_fat
= (section_header
& METHOD_HEADER_SECTION_FAT_FORMAT
) != 0;
2261 section_size
= (section_header
>> 8) & (is_fat
? 0xFFFFFF : 0xFF);
2263 if (section_size
< 4)
2264 FAIL (ctx
, g_strdup_printf ("MethodHeader: Section size too small"));
2266 if (ADDP_IS_GREATER_OR_OVF (ptr
, section_size
- 4, end
)) /*must be section_size -4 as ptr was incremented by safe_read32*/
2267 FAIL (ctx
, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size
));
2269 if (section_header
& METHOD_HEADER_SECTION_EHTABLE
) {
2270 guint32 i
, clauses
= section_size
/ (is_fat
? 24 : 12);
2272 LAMEIMPL: MS emits section_size without accounting for header size.
2273 Mono does as the spec says. section_size is header + section
2274 MS's peverify happily accepts both.
2276 if ((clauses
* (is_fat
? 24 : 12) != section_size
) && (clauses
* (is_fat
? 24 : 12) + 4 != section_size
))
2277 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)));
2279 /* only verify the class token is verified as the rest is done by the IL verifier*/
2280 for (i
= 0; i
< clauses
; ++i
) {
2281 unsigned flags
= *(unsigned char*)ptr
;
2282 unsigned class_token
= 0;
2283 ptr
+= (is_fat
? 20 : 8);
2284 if (!safe_read32 (class_token
, ptr
, end
))
2285 FAIL (ctx
, g_strdup_printf ("MethodHeader: Not enough room for section %d", i
));
2286 if (flags
== MONO_EXCEPTION_CLAUSE_NONE
&& class_token
) {
2287 guint table
= mono_metadata_token_table (class_token
);
2288 if (table
!= MONO_TABLE_TYPEREF
&& table
!= MONO_TABLE_TYPEDEF
&& table
!= MONO_TABLE_TYPESPEC
)
2289 FAIL (ctx
, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i
, table
));
2290 if (mono_metadata_token_index (class_token
) > ctx
->image
->tables
[table
].rows
)
2291 FAIL (ctx
, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i
, mono_metadata_token_index (class_token
)));
2296 if (!(section_header
& METHOD_HEADER_SECTION_MORE_SECTS
))
2303 verify_module_table (VerifyContext
*ctx
)
2305 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_MODULE
];
2306 guint32 data
[MONO_MODULE_SIZE
];
2308 if (table
->rows
!= 1)
2309 ADD_ERROR (ctx
, g_strdup_printf ("Module table must have exactly one row, but have %d", table
->rows
));
2311 mono_metadata_decode_row (table
, 0, data
, MONO_MODULE_SIZE
);
2313 if (!is_valid_non_empty_string (ctx
, data
[MONO_MODULE_NAME
]))
2314 ADD_ERROR (ctx
, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data
[MONO_MODULE_NAME
]));
2316 if (!is_valid_guid (ctx
, data
[MONO_MODULE_MVID
]))
2317 ADD_ERROR (ctx
, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data
[MONO_MODULE_MVID
]));
2319 if (data
[MONO_MODULE_ENC
] != 0)
2320 ADD_ERROR (ctx
, g_strdup_printf ("Module has a non zero Enc field %x", data
[MONO_MODULE_ENC
]));
2322 if (data
[MONO_MODULE_ENCBASE
] != 0)
2323 ADD_ERROR (ctx
, g_strdup_printf ("Module has a non zero EncBase field %x", data
[MONO_MODULE_ENCBASE
]));
2327 verify_typeref_table (VerifyContext
*ctx
)
2329 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_TYPEREF
];
2330 guint32 data
[MONO_TYPEREF_SIZE
];
2333 for (i
= 0; i
< table
->rows
; ++i
) {
2334 mono_metadata_decode_row (table
, i
, data
, MONO_TYPEREF_SIZE
);
2335 if (!is_valid_coded_index (ctx
, RES_SCOPE_DESC
, data
[MONO_TYPEREF_SCOPE
]))
2336 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i
, data
[MONO_TYPEREF_SCOPE
]));
2338 if (!get_coded_index_token (RES_SCOPE_DESC
, data
[MONO_TYPEREF_SCOPE
]))
2339 ADD_ERROR (ctx
, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i
));
2341 if (!data
[MONO_TYPEREF_NAME
] || !is_valid_non_empty_string (ctx
, data
[MONO_TYPEREF_NAME
]))
2342 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i
, data
[MONO_TYPEREF_NAME
]));
2344 if (data
[MONO_TYPEREF_NAMESPACE
] && !is_valid_non_empty_string (ctx
, data
[MONO_TYPEREF_NAMESPACE
]))
2345 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i
, data
[MONO_TYPEREF_NAMESPACE
]));
2349 /*bits 9,11,14,15,19,21,24-31 */
2350 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2352 verify_typedef_table (VerifyContext
*ctx
)
2354 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_TYPEDEF
];
2355 guint32 data
[MONO_TYPEDEF_SIZE
];
2356 guint32 fieldlist
= 1, methodlist
= 1, visibility
;
2359 if (table
->rows
== 0)
2360 ADD_ERROR (ctx
, g_strdup_printf ("Typedef table must have exactly at least one row"));
2362 for (i
= 0; i
< table
->rows
; ++i
) {
2363 mono_metadata_decode_row (table
, i
, data
, MONO_TYPEDEF_SIZE
);
2364 if (data
[MONO_TYPEDEF_FLAGS
] & INVALID_TYPEDEF_FLAG_BITS
)
2365 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i
, data
[MONO_TYPEDEF_FLAGS
]));
2367 if ((data
[MONO_TYPEDEF_FLAGS
] & TYPE_ATTRIBUTE_LAYOUT_MASK
) == 0x18)
2368 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i
));
2370 if ((data
[MONO_TYPEDEF_FLAGS
] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK
) == 0x30000)
2371 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i
));
2373 if ((data
[MONO_TYPEDEF_FLAGS
] & 0xC00000) != 0)
2374 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i
));
2376 if ((data
[MONO_TYPEDEF_FLAGS
] & TYPE_ATTRIBUTE_INTERFACE
) && (data
[MONO_TYPEDEF_FLAGS
] & TYPE_ATTRIBUTE_ABSTRACT
) == 0)
2377 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i
));
2379 if (!data
[MONO_TYPEDEF_NAME
] || !is_valid_non_empty_string (ctx
, data
[MONO_TYPEDEF_NAME
]))
2380 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i
, data
[MONO_TYPEDEF_NAME
]));
2382 if (data
[MONO_TYPEREF_NAMESPACE
] && !is_valid_non_empty_string (ctx
, data
[MONO_TYPEREF_NAMESPACE
]))
2383 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i
, data
[MONO_TYPEREF_NAMESPACE
]));
2385 if (data
[MONO_TYPEDEF_EXTENDS
] && !is_valid_coded_index (ctx
, TYPEDEF_OR_REF_DESC
, data
[MONO_TYPEDEF_EXTENDS
]))
2386 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i
, data
[MONO_TYPEDEF_EXTENDS
]));
2388 visibility
= data
[MONO_TYPEDEF_FLAGS
] & TYPE_ATTRIBUTE_VISIBILITY_MASK
;
2389 if ((visibility
>= TYPE_ATTRIBUTE_NESTED_PUBLIC
&& visibility
<= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM
) &&
2390 search_sorted_table (ctx
, MONO_TABLE_NESTEDCLASS
, MONO_NESTED_CLASS_NESTED
, i
+ 1) == -1)
2391 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i
));
2393 if (data
[MONO_TYPEDEF_FIELD_LIST
] == 0)
2394 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i
));
2396 if (data
[MONO_TYPEDEF_FIELD_LIST
] > ctx
->image
->tables
[MONO_TABLE_FIELD
].rows
+ 1)
2397 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i
, data
[MONO_TYPEDEF_FIELD_LIST
]));
2399 if (data
[MONO_TYPEDEF_FIELD_LIST
] < fieldlist
)
2400 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
));
2402 if (data
[MONO_TYPEDEF_METHOD_LIST
] == 0)
2403 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i
));
2405 if (data
[MONO_TYPEDEF_METHOD_LIST
] > ctx
->image
->tables
[MONO_TABLE_METHOD
].rows
+ 1)
2406 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i
, data
[MONO_TYPEDEF_METHOD_LIST
]));
2408 if (data
[MONO_TYPEDEF_METHOD_LIST
] < methodlist
)
2409 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
));
2411 fieldlist
= data
[MONO_TYPEDEF_FIELD_LIST
];
2412 methodlist
= data
[MONO_TYPEDEF_METHOD_LIST
];
2417 verify_typedef_table_full (VerifyContext
*ctx
)
2419 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_TYPEDEF
];
2420 guint32 data
[MONO_TYPEDEF_SIZE
];
2423 if (table
->rows
== 0)
2424 ADD_ERROR (ctx
, g_strdup_printf ("Typedef table must have exactly at least one row"));
2426 for (i
= 0; i
< table
->rows
; ++i
) {
2427 mono_metadata_decode_row (table
, i
, data
, MONO_TYPEDEF_SIZE
);
2430 /*XXX it's ok if <module> extends object, or anything at all, actually. */
2431 /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
2432 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2437 if (data
[MONO_TYPEDEF_FLAGS
] & TYPE_ATTRIBUTE_INTERFACE
) {
2438 if (data
[MONO_TYPEDEF_EXTENDS
])
2439 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i
));
2441 gboolean is_sys_obj
= typedef_is_system_object (ctx
, data
);
2442 gboolean has_parent
= get_coded_index_token (TYPEDEF_OR_REF_DESC
, data
[MONO_TYPEDEF_EXTENDS
]) != 0;
2446 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i
));
2449 ADD_ERROR (ctx
, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i
));
2457 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2459 verify_field_table (VerifyContext
*ctx
)
2461 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_FIELD
];
2462 guint32 data
[MONO_FIELD_SIZE
], flags
, module_field_list
;
2465 module_field_list
= (guint32
)-1;
2466 if (ctx
->image
->tables
[MONO_TABLE_TYPEDEF
].rows
> 1) {
2467 MonoTableInfo
*type
= &ctx
->image
->tables
[MONO_TABLE_TYPEDEF
];
2468 module_field_list
= mono_metadata_decode_row_col (type
, 1, MONO_TYPEDEF_FIELD_LIST
);
2471 for (i
= 0; i
< table
->rows
; ++i
) {
2472 mono_metadata_decode_row (table
, i
, data
, MONO_FIELD_SIZE
);
2473 flags
= data
[MONO_FIELD_FLAGS
];
2475 if (flags
& INVALID_FIELD_FLAG_BITS
)
2476 ADD_ERROR (ctx
, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i
, flags
));
2478 if ((flags
& FIELD_ATTRIBUTE_FIELD_ACCESS_MASK
) == 0x7)
2479 ADD_ERROR (ctx
, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i
));
2481 if ((flags
& (FIELD_ATTRIBUTE_LITERAL
| FIELD_ATTRIBUTE_INIT_ONLY
)) == (FIELD_ATTRIBUTE_LITERAL
| FIELD_ATTRIBUTE_INIT_ONLY
))
2482 ADD_ERROR (ctx
, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i
));
2484 if ((flags
& FIELD_ATTRIBUTE_RT_SPECIAL_NAME
) && !(flags
& FIELD_ATTRIBUTE_SPECIAL_NAME
))
2485 ADD_ERROR (ctx
, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i
));
2487 if ((flags
& FIELD_ATTRIBUTE_LITERAL
) && !(flags
& FIELD_ATTRIBUTE_STATIC
))
2488 ADD_ERROR (ctx
, g_strdup_printf ("Invalid field row %d is Literal but not Static", i
));
2490 if ((flags
& FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL
) &&
2491 search_sorted_table (ctx
, MONO_TABLE_FIELDMARSHAL
, MONO_FIELD_MARSHAL_PARENT
, make_coded_token (HAS_FIELD_MARSHAL_DESC
, MONO_TABLE_FIELD
, i
)) == -1)
2492 ADD_ERROR (ctx
, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i
));
2494 if ((flags
& FIELD_ATTRIBUTE_HAS_DEFAULT
) &&
2495 search_sorted_table (ctx
, MONO_TABLE_CONSTANT
, MONO_CONSTANT_PARENT
, make_coded_token (HAS_CONSTANT_DESC
, MONO_TABLE_FIELD
, i
)) == -1)
2496 ADD_ERROR (ctx
, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i
));
2498 if ((flags
& FIELD_ATTRIBUTE_LITERAL
) &&
2499 search_sorted_table (ctx
, MONO_TABLE_CONSTANT
, MONO_CONSTANT_PARENT
, make_coded_token (HAS_CONSTANT_DESC
, MONO_TABLE_FIELD
, i
)) == -1)
2500 ADD_ERROR (ctx
, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i
));
2502 if ((flags
& FIELD_ATTRIBUTE_HAS_FIELD_RVA
) &&
2503 search_sorted_table (ctx
, MONO_TABLE_FIELDRVA
, MONO_FIELD_RVA_FIELD
, i
+ 1) == -1)
2504 ADD_ERROR (ctx
, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i
));
2506 if (!data
[MONO_FIELD_NAME
] || !is_valid_non_empty_string (ctx
, data
[MONO_FIELD_NAME
]))
2507 ADD_ERROR (ctx
, g_strdup_printf ("Invalid field row %d invalid name token %08x", i
, data
[MONO_FIELD_NAME
]));
2509 if (data
[MONO_FIELD_SIGNATURE
] && !is_valid_blob_object (ctx
, data
[MONO_FIELD_SIGNATURE
], 1))
2510 ADD_ERROR (ctx
, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i
, data
[MONO_FIELD_SIGNATURE
]));
2512 //TODO verify contant flag
2514 if (i
+ 1 < module_field_list
) {
2515 guint32 access
= flags
& FIELD_ATTRIBUTE_FIELD_ACCESS_MASK
;
2516 if (!(flags
& FIELD_ATTRIBUTE_STATIC
))
2517 ADD_ERROR (ctx
, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i
));
2518 if (access
!= FIELD_ATTRIBUTE_COMPILER_CONTROLLED
&& access
!= FIELD_ATTRIBUTE_PRIVATE
&& access
!= FIELD_ATTRIBUTE_PUBLIC
)
2519 ADD_ERROR (ctx
, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i
, access
));
2525 verify_field_table_full (VerifyContext
*ctx
)
2527 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_FIELD
];
2528 guint32 data
[MONO_FIELD_SIZE
];
2531 for (i
= 0; i
< table
->rows
; ++i
) {
2532 mono_metadata_decode_row (table
, i
, data
, MONO_FIELD_SIZE
);
2534 if (!data
[MONO_FIELD_SIGNATURE
] || !is_valid_field_signature (ctx
, data
[MONO_FIELD_SIGNATURE
]))
2535 ADD_ERROR (ctx
, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i
, data
[MONO_FIELD_SIGNATURE
]));
2539 /*bits 8,9,10,11,13,14,15*/
2540 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2542 verify_method_table (VerifyContext
*ctx
)
2544 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_METHOD
];
2545 guint32 data
[MONO_METHOD_SIZE
], flags
, implflags
, rva
, module_method_list
, access
, code_type
;
2546 guint32 paramlist
= 1;
2547 gboolean is_ctor
, is_cctor
;
2551 module_method_list
= (guint32
)-1;
2552 if (ctx
->image
->tables
[MONO_TABLE_TYPEDEF
].rows
> 1) {
2553 MonoTableInfo
*type
= &ctx
->image
->tables
[MONO_TABLE_TYPEDEF
];
2554 module_method_list
= mono_metadata_decode_row_col (type
, 1, MONO_TYPEDEF_METHOD_LIST
);
2557 for (i
= 0; i
< table
->rows
; ++i
) {
2558 mono_metadata_decode_row (table
, i
, data
, MONO_METHOD_SIZE
);
2559 rva
= data
[MONO_METHOD_RVA
];
2560 implflags
= data
[MONO_METHOD_IMPLFLAGS
];
2561 flags
= data
[MONO_METHOD_FLAGS
];
2562 access
= flags
& METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK
;
2563 code_type
= implflags
& METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK
;
2566 if (implflags
& INVALID_METHOD_IMPLFLAG_BITS
)
2567 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i
, implflags
));
2570 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i
));
2572 if (!data
[MONO_METHOD_NAME
] || !is_valid_non_empty_string (ctx
, data
[MONO_METHOD_NAME
]))
2573 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i
, data
[MONO_METHOD_NAME
]));
2575 name
= get_string_ptr (ctx
, data
[MONO_METHOD_NAME
]);
2576 is_ctor
= !strcmp (".ctor", name
);
2577 is_cctor
= !strcmp (".cctor", name
);
2579 if ((is_ctor
|| is_cctor
) &&
2580 search_sorted_table (ctx
, MONO_TABLE_GENERICPARAM
, MONO_GENERICPARAM_OWNER
, make_coded_token (TYPE_OR_METHODDEF_DESC
, MONO_TABLE_METHOD
, i
)) != -1)
2581 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i
));
2583 if ((flags
& METHOD_ATTRIBUTE_STATIC
) && (flags
& (METHOD_ATTRIBUTE_FINAL
| METHOD_ATTRIBUTE_VIRTUAL
| METHOD_ATTRIBUTE_NEW_SLOT
)))
2584 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i
));
2586 if (flags
& METHOD_ATTRIBUTE_ABSTRACT
) {
2587 if (flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
2588 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i
));
2589 if (flags
& METHOD_ATTRIBUTE_FINAL
)
2590 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is Abstract and Final", i
));
2591 if (!(flags
& METHOD_ATTRIBUTE_VIRTUAL
))
2592 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i
));
2595 if (access
== METHOD_ATTRIBUTE_COMPILER_CONTROLLED
&& (flags
& (METHOD_ATTRIBUTE_RT_SPECIAL_NAME
| METHOD_ATTRIBUTE_SPECIAL_NAME
)))
2596 ADD_WARNING (ctx
, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i
));
2598 if ((flags
& METHOD_ATTRIBUTE_RT_SPECIAL_NAME
) && !(flags
& METHOD_ATTRIBUTE_SPECIAL_NAME
))
2599 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i
));
2601 //XXX no checks against cas stuff 10,11,12,13)
2603 //TODO check iface with .ctor (15,16)
2605 if (i
+ 1 < module_method_list
) {
2606 if (!(flags
& METHOD_ATTRIBUTE_STATIC
))
2607 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is a global method but not Static", i
));
2608 if (flags
& (METHOD_ATTRIBUTE_ABSTRACT
| METHOD_ATTRIBUTE_VIRTUAL
))
2609 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i
));
2610 if (!(access
== METHOD_ATTRIBUTE_COMPILER_CONTROLLED
|| access
== METHOD_ATTRIBUTE_PUBLIC
|| access
== METHOD_ATTRIBUTE_PRIVATE
))
2611 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i
));
2614 //TODO check valuetype for synchronized
2616 if ((flags
& (METHOD_ATTRIBUTE_FINAL
| METHOD_ATTRIBUTE_NEW_SLOT
| METHOD_ATTRIBUTE_STRICT
)) && !(flags
& METHOD_ATTRIBUTE_VIRTUAL
))
2617 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i
));
2619 if (flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
2620 if (flags
& METHOD_ATTRIBUTE_VIRTUAL
)
2621 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i
));
2622 if (!(flags
& METHOD_ATTRIBUTE_STATIC
))
2623 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i
));
2626 if (!(flags
& METHOD_ATTRIBUTE_ABSTRACT
) && !rva
&& !(flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) &&
2627 !(implflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) && code_type
!= METHOD_IMPL_ATTRIBUTE_RUNTIME
)
2628 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i
));
2630 if (access
== METHOD_ATTRIBUTE_COMPILER_CONTROLLED
&& !(rva
|| (flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)))
2631 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i
));
2633 //TODO check signature contents
2636 if (flags
& METHOD_ATTRIBUTE_ABSTRACT
)
2637 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i
));
2638 if (code_type
== METHOD_IMPL_ATTRIBUTE_OPTIL
)
2639 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i
));
2641 if (!(flags
& (METHOD_ATTRIBUTE_ABSTRACT
| METHOD_ATTRIBUTE_PINVOKE_IMPL
)) && !(implflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) && code_type
!= METHOD_IMPL_ATTRIBUTE_RUNTIME
)
2642 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i
));
2645 if ((flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)) {
2647 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i
));
2648 if (search_sorted_table (ctx
, MONO_TABLE_IMPLMAP
, MONO_IMPLMAP_MEMBER
, make_coded_token (MEMBER_FORWARDED_DESC
, MONO_TABLE_METHOD
, i
)) == -1)
2649 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i
));
2651 if (flags
& METHOD_ATTRIBUTE_RT_SPECIAL_NAME
&& !is_ctor
&& !is_cctor
)
2652 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i
));
2654 if ((is_ctor
|| is_cctor
) && !(flags
& METHOD_ATTRIBUTE_RT_SPECIAL_NAME
))
2655 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i
));
2657 if (data
[MONO_METHOD_SIGNATURE
] && !is_valid_blob_object (ctx
, data
[MONO_METHOD_SIGNATURE
], 1))
2658 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i
, data
[MONO_METHOD_SIGNATURE
]));
2660 if (data
[MONO_METHOD_PARAMLIST
] == 0)
2661 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i
));
2663 if (data
[MONO_METHOD_PARAMLIST
] < paramlist
)
2664 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
));
2666 if (data
[MONO_METHOD_PARAMLIST
] > ctx
->image
->tables
[MONO_TABLE_PARAM
].rows
+ 1)
2667 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i
, data
[MONO_METHOD_PARAMLIST
]));
2669 paramlist
= data
[MONO_METHOD_PARAMLIST
];
2675 verify_method_table_full (VerifyContext
*ctx
)
2677 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_METHOD
];
2678 guint32 data
[MONO_METHOD_SIZE
], rva
;
2681 for (i
= 0; i
< table
->rows
; ++i
) {
2682 mono_metadata_decode_row (table
, i
, data
, MONO_METHOD_SIZE
);
2683 rva
= data
[MONO_METHOD_RVA
];
2685 if (!data
[MONO_METHOD_SIGNATURE
] || !is_valid_method_signature (ctx
, data
[MONO_METHOD_SIGNATURE
]))
2686 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i
, data
[MONO_METHOD_SIGNATURE
]));
2688 if (rva
&& !is_valid_method_header (ctx
, rva
))
2689 ADD_ERROR (ctx
, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i
));
2694 get_next_param_count (VerifyContext
*ctx
, guint32
*current_method
)
2696 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_METHOD
];
2697 guint32 row
= *current_method
;
2698 guint32 paramlist
, tmp
;
2701 paramlist
= mono_metadata_decode_row_col (table
, row
++, MONO_METHOD_PARAMLIST
);
2702 while (row
< table
->rows
) {
2703 tmp
= mono_metadata_decode_row_col (table
, row
, MONO_METHOD_PARAMLIST
);
2704 if (tmp
> paramlist
) {
2705 *current_method
= row
;
2706 return tmp
- paramlist
;
2711 /*no more methods, all params apply to the last one*/
2712 *current_method
= table
->rows
;
2717 #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))
2719 verify_param_table (VerifyContext
*ctx
)
2721 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_PARAM
];
2722 guint32 data
[MONO_PARAM_SIZE
], flags
, sequence
= 0, remaining_params
, current_method
= 0;
2723 gboolean first_param
= TRUE
;
2726 if (ctx
->image
->tables
[MONO_TABLE_METHOD
].rows
== 0) {
2727 if (table
->rows
> 0)
2728 ADD_ERROR (ctx
, g_strdup ("Param table has rows while the method table has zero"));
2732 remaining_params
= get_next_param_count (ctx
, ¤t_method
);
2734 for (i
= 0; i
< table
->rows
; ++i
) {
2735 mono_metadata_decode_row (table
, i
, data
, MONO_PARAM_SIZE
);
2736 flags
= data
[MONO_PARAM_FLAGS
];
2738 if (flags
& INVALID_PARAM_FLAGS_BITS
)
2739 ADD_ERROR (ctx
, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i
, flags
));
2741 if (search_sorted_table (ctx
, MONO_TABLE_CONSTANT
, MONO_CONSTANT_PARENT
, make_coded_token (HAS_CONSTANT_DESC
, MONO_TABLE_PARAM
, i
)) == -1) {
2742 if (flags
& PARAM_ATTRIBUTE_HAS_DEFAULT
)
2743 ADD_ERROR (ctx
, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i
));
2745 if (!(flags
& PARAM_ATTRIBUTE_HAS_DEFAULT
))
2746 ADD_ERROR (ctx
, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i
));
2749 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)
2750 ADD_ERROR (ctx
, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i
));
2752 if (!is_valid_string (ctx
, data
[MONO_PARAM_NAME
]))
2753 ADD_ERROR (ctx
, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i
, data
[MONO_PARAM_NAME
]));
2755 if (!first_param
&& data
[MONO_PARAM_SEQUENCE
] <= sequence
)
2756 ADD_ERROR (ctx
, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i
, data
[MONO_PARAM_SEQUENCE
], sequence
));
2758 first_param
= FALSE
;
2759 sequence
= data
[MONO_PARAM_SEQUENCE
];
2760 if (--remaining_params
== 0) {
2761 remaining_params
= get_next_param_count (ctx
, ¤t_method
);
2768 verify_interfaceimpl_table (VerifyContext
*ctx
)
2770 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_INTERFACEIMPL
];
2771 guint32 data
[MONO_INTERFACEIMPL_SIZE
];
2774 for (i
= 0; i
< table
->rows
; ++i
) {
2775 mono_metadata_decode_row (table
, i
, data
, MONO_INTERFACEIMPL_SIZE
);
2776 if (data
[MONO_INTERFACEIMPL_CLASS
] && data
[MONO_INTERFACEIMPL_CLASS
] > ctx
->image
->tables
[MONO_TABLE_TYPEDEF
].rows
)
2777 ADD_ERROR (ctx
, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i
, data
[MONO_TABLE_TYPEDEF
]));
2779 if (!is_valid_coded_index (ctx
, TYPEDEF_OR_REF_DESC
, data
[MONO_INTERFACEIMPL_INTERFACE
]))
2780 ADD_ERROR (ctx
, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i
, data
[MONO_INTERFACEIMPL_INTERFACE
]));
2782 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC
, data
[MONO_INTERFACEIMPL_INTERFACE
]))
2783 ADD_ERROR (ctx
, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i
));
2788 verify_memberref_table (VerifyContext
*ctx
)
2790 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_MEMBERREF
];
2791 guint32 data
[MONO_MEMBERREF_SIZE
];
2794 for (i
= 0; i
< table
->rows
; ++i
) {
2795 mono_metadata_decode_row (table
, i
, data
, MONO_MEMBERREF_SIZE
);
2797 if (!is_valid_coded_index (ctx
, MEMBERREF_PARENT_DESC
, data
[MONO_MEMBERREF_CLASS
]))
2798 ADD_ERROR (ctx
, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i
, data
[MONO_MEMBERREF_CLASS
]));
2800 if (!get_coded_index_token (MEMBERREF_PARENT_DESC
, data
[MONO_MEMBERREF_CLASS
]))
2801 ADD_ERROR (ctx
, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i
));
2803 if (!is_valid_non_empty_string (ctx
, data
[MONO_MEMBERREF_NAME
]))
2804 ADD_ERROR (ctx
, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i
, data
[MONO_MEMBERREF_NAME
]));
2806 if (data
[MONO_MEMBERREF_SIGNATURE
] && !is_valid_blob_object (ctx
, data
[MONO_MEMBERREF_SIGNATURE
], 1))
2807 ADD_ERROR (ctx
, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i
, data
[MONO_MEMBERREF_SIGNATURE
]));
2813 verify_memberref_table_full (VerifyContext
*ctx
)
2815 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_MEMBERREF
];
2816 guint32 data
[MONO_MEMBERREF_SIZE
];
2819 for (i
= 0; i
< table
->rows
; ++i
) {
2820 mono_metadata_decode_row (table
, i
, data
, MONO_MEMBERREF_SIZE
);
2822 if (!is_valid_method_or_field_signature (ctx
, data
[MONO_MEMBERREF_SIGNATURE
]))
2823 ADD_ERROR (ctx
, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i
, data
[MONO_MEMBERREF_SIGNATURE
]));
2828 verify_constant_table (VerifyContext
*ctx
)
2830 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_CONSTANT
];
2831 guint32 data
[MONO_CONSTANT_SIZE
], type
;
2834 for (i
= 0; i
< table
->rows
; ++i
) {
2835 mono_metadata_decode_row (table
, i
, data
, MONO_CONSTANT_SIZE
);
2836 type
= data
[MONO_CONSTANT_TYPE
];
2838 if (!((type
>= MONO_TYPE_BOOLEAN
&& type
<= MONO_TYPE_STRING
) || type
== MONO_TYPE_CLASS
))
2839 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i
, type
));
2841 if (!is_valid_coded_index (ctx
, HAS_CONSTANT_DESC
, data
[MONO_CONSTANT_PARENT
]))
2842 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i
, data
[MONO_CONSTANT_PARENT
]));
2844 if (!get_coded_index_token (HAS_CONSTANT_DESC
, data
[MONO_CONSTANT_PARENT
]))
2845 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i
));
2847 if (!is_valid_constant (ctx
, type
, data
[MONO_CONSTANT_VALUE
]))
2848 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i
, data
[MONO_CONSTANT_VALUE
]));
2853 verify_cattr_table (VerifyContext
*ctx
)
2855 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_CUSTOMATTRIBUTE
];
2856 guint32 data
[MONO_CUSTOM_ATTR_SIZE
];
2859 for (i
= 0; i
< table
->rows
; ++i
) {
2860 mono_metadata_decode_row (table
, i
, data
, MONO_CUSTOM_ATTR_SIZE
);
2862 if (!is_valid_coded_index (ctx
, HAS_CATTR_DESC
, data
[MONO_CUSTOM_ATTR_PARENT
]))
2863 ADD_ERROR (ctx
, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i
, data
[MONO_CUSTOM_ATTR_PARENT
]));
2865 if (!is_valid_coded_index (ctx
, CATTR_TYPE_DESC
, data
[MONO_CUSTOM_ATTR_TYPE
]))
2866 ADD_ERROR (ctx
, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i
, data
[MONO_CUSTOM_ATTR_PARENT
]));
2868 if (data
[MONO_CUSTOM_ATTR_VALUE
] && !is_valid_blob_object (ctx
, data
[MONO_CUSTOM_ATTR_VALUE
], 0))
2869 ADD_ERROR (ctx
, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i
, data
[MONO_CUSTOM_ATTR_VALUE
]));
2874 verify_cattr_table_full (VerifyContext
*ctx
)
2876 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_CUSTOMATTRIBUTE
];
2879 guint32 data
[MONO_CUSTOM_ATTR_SIZE
], mtoken
, size
;
2882 for (i
= 0; i
< table
->rows
; ++i
) {
2883 mono_metadata_decode_row (table
, i
, data
, MONO_CUSTOM_ATTR_SIZE
);
2885 if (!is_valid_cattr_blob (ctx
, data
[MONO_CUSTOM_ATTR_VALUE
]))
2886 ADD_ERROR (ctx
, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i
, data
[MONO_CUSTOM_ATTR_VALUE
]));
2888 mtoken
= data
[MONO_CUSTOM_ATTR_TYPE
] >> MONO_CUSTOM_ATTR_TYPE_BITS
;
2889 switch (data
[MONO_CUSTOM_ATTR_TYPE
] & MONO_CUSTOM_ATTR_TYPE_MASK
) {
2890 case MONO_CUSTOM_ATTR_TYPE_METHODDEF
:
2891 mtoken
|= MONO_TOKEN_METHOD_DEF
;
2893 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF
:
2894 mtoken
|= MONO_TOKEN_MEMBER_REF
;
2897 ADD_ERROR (ctx
, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i
, data
[MONO_CUSTOM_ATTR_TYPE
]));
2900 ctor
= mono_get_method (ctx
->image
, mtoken
, NULL
);
2902 /*This can't fail since this is checked in is_valid_cattr_blob*/
2903 g_assert (decode_signature_header (ctx
, data
[MONO_CUSTOM_ATTR_VALUE
], &size
, &ptr
));
2905 if (!is_valid_cattr_content (ctx
, ctor
, ptr
, size
))
2906 ADD_ERROR (ctx
, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x", i
, data
[MONO_CUSTOM_ATTR_VALUE
]));
2911 verify_field_marshal_table (VerifyContext
*ctx
)
2913 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_FIELDMARSHAL
];
2914 guint32 data
[MONO_FIELD_MARSHAL_SIZE
];
2917 for (i
= 0; i
< table
->rows
; ++i
) {
2918 mono_metadata_decode_row (table
, i
, data
, MONO_FIELD_MARSHAL_SIZE
);
2920 if (!is_valid_coded_index (ctx
, HAS_FIELD_MARSHAL_DESC
, data
[MONO_FIELD_MARSHAL_PARENT
]))
2921 ADD_ERROR (ctx
, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i
, data
[MONO_FIELD_MARSHAL_PARENT
]));
2923 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC
, data
[MONO_FIELD_MARSHAL_PARENT
]))
2924 ADD_ERROR (ctx
, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i
));
2926 if (!data
[MONO_FIELD_MARSHAL_NATIVE_TYPE
])
2927 ADD_ERROR (ctx
, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i
));
2929 if (!is_valid_blob_object (ctx
, data
[MONO_FIELD_MARSHAL_NATIVE_TYPE
], 1))
2930 ADD_ERROR (ctx
, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i
, data
[MONO_FIELD_MARSHAL_NATIVE_TYPE
]));
2935 verify_field_marshal_table_full (VerifyContext
*ctx
)
2937 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_FIELDMARSHAL
];
2938 guint32 data
[MONO_FIELD_MARSHAL_SIZE
];
2941 for (i
= 0; i
< table
->rows
; ++i
) {
2942 mono_metadata_decode_row (table
, i
, data
, MONO_FIELD_MARSHAL_SIZE
);
2944 if (!is_valid_marshal_spec (ctx
, data
[MONO_FIELD_MARSHAL_NATIVE_TYPE
]))
2945 ADD_ERROR (ctx
, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i
, data
[MONO_FIELD_MARSHAL_NATIVE_TYPE
]));
2950 verify_decl_security_table (VerifyContext
*ctx
)
2952 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_DECLSECURITY
];
2953 guint32 data
[MONO_DECL_SECURITY_SIZE
];
2956 for (i
= 0; i
< table
->rows
; ++i
) {
2957 mono_metadata_decode_row (table
, i
, data
, MONO_DECL_SECURITY_SIZE
);
2959 if (!is_valid_coded_index (ctx
, HAS_DECL_SECURITY_DESC
, data
[MONO_DECL_SECURITY_PARENT
]))
2960 ADD_ERROR (ctx
, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i
, data
[MONO_DECL_SECURITY_PARENT
]));
2962 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC
, data
[MONO_DECL_SECURITY_PARENT
]))
2963 ADD_ERROR (ctx
, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i
));
2965 if (!data
[MONO_DECL_SECURITY_PERMISSIONSET
])
2966 ADD_ERROR (ctx
, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i
));
2971 verify_decl_security_table_full (VerifyContext
*ctx
)
2973 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_DECLSECURITY
];
2974 guint32 data
[MONO_DECL_SECURITY_SIZE
];
2977 for (i
= 0; i
< table
->rows
; ++i
) {
2978 mono_metadata_decode_row (table
, i
, data
, MONO_DECL_SECURITY_SIZE
);
2980 if (!is_valid_permission_set (ctx
, data
[MONO_DECL_SECURITY_PERMISSIONSET
]))
2981 ADD_ERROR (ctx
, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i
, data
[MONO_DECL_SECURITY_PERMISSIONSET
]));
2986 verify_class_layout_table (VerifyContext
*ctx
)
2988 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_CLASSLAYOUT
];
2989 guint32 data
[MONO_CLASS_LAYOUT_SIZE
];
2992 for (i
= 0; i
< table
->rows
; ++i
) {
2993 mono_metadata_decode_row (table
, i
, data
, MONO_CLASS_LAYOUT_SIZE
);
2995 if (!data
[MONO_CLASS_LAYOUT_PARENT
] || data
[MONO_CLASS_LAYOUT_PARENT
] > ctx
->image
->tables
[MONO_TABLE_TYPEDEF
].rows
+ 1)
2996 ADD_ERROR (ctx
, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i
, data
[MONO_TABLE_TYPEDEF
]));
2998 switch (data
[MONO_CLASS_LAYOUT_PACKING_SIZE
]) {
3010 ADD_ERROR (ctx
, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i
, data
[MONO_CLASS_LAYOUT_PACKING_SIZE
]));
3016 verify_field_layout_table (VerifyContext
*ctx
)
3018 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_FIELDLAYOUT
];
3019 guint32 data
[MONO_FIELD_LAYOUT_SIZE
];
3022 for (i
= 0; i
< table
->rows
; ++i
) {
3023 mono_metadata_decode_row (table
, i
, data
, MONO_FIELD_LAYOUT_SIZE
);
3025 if (!data
[MONO_FIELD_LAYOUT_FIELD
] || data
[MONO_FIELD_LAYOUT_FIELD
] > ctx
->image
->tables
[MONO_TABLE_FIELD
].rows
+ 1)
3026 ADD_ERROR (ctx
, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i
, data
[MONO_FIELD_LAYOUT_FIELD
]));
3031 verify_standalonesig_table (VerifyContext
*ctx
)
3033 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_STANDALONESIG
];
3034 guint32 data
[MONO_STAND_ALONE_SIGNATURE_SIZE
];
3037 for (i
= 0; i
< table
->rows
; ++i
) {
3038 mono_metadata_decode_row (table
, i
, data
, MONO_STAND_ALONE_SIGNATURE_SIZE
);
3040 if (data
[MONO_STAND_ALONE_SIGNATURE
] && !is_valid_blob_object (ctx
, data
[MONO_STAND_ALONE_SIGNATURE
], 1))
3041 ADD_ERROR (ctx
, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i
, data
[MONO_STAND_ALONE_SIGNATURE
]));
3046 verify_standalonesig_table_full (VerifyContext
*ctx
)
3048 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_STANDALONESIG
];
3049 guint32 data
[MONO_STAND_ALONE_SIGNATURE_SIZE
];
3052 for (i
= 0; i
< table
->rows
; ++i
) {
3053 mono_metadata_decode_row (table
, i
, data
, MONO_STAND_ALONE_SIGNATURE_SIZE
);
3055 if (!is_valid_standalonesig_blob (ctx
, data
[MONO_STAND_ALONE_SIGNATURE
]))
3056 ADD_ERROR (ctx
, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i
, data
[MONO_STAND_ALONE_SIGNATURE
]));
3061 verify_eventmap_table (VerifyContext
*ctx
)
3063 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_EVENTMAP
];
3064 guint32 data
[MONO_EVENT_MAP_SIZE
], eventlist
= 0;
3067 for (i
= 0; i
< table
->rows
; ++i
) {
3068 mono_metadata_decode_row (table
, i
, data
, MONO_EVENT_MAP_SIZE
);
3070 if (!data
[MONO_EVENT_MAP_PARENT
] || data
[MONO_EVENT_MAP_PARENT
] > ctx
->image
->tables
[MONO_TABLE_TYPEDEF
].rows
+ 1)
3071 ADD_ERROR (ctx
, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i
, data
[MONO_EVENT_MAP_PARENT
]));
3073 if (!data
[MONO_EVENT_MAP_EVENTLIST
] || data
[MONO_EVENT_MAP_EVENTLIST
] <= eventlist
)
3074 ADD_ERROR (ctx
, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i
, data
[MONO_EVENT_MAP_EVENTLIST
]));
3076 eventlist
= data
[MONO_EVENT_MAP_EVENTLIST
];
3080 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3082 verify_event_table (VerifyContext
*ctx
)
3084 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_EVENT
];
3085 guint32 data
[MONO_EVENT_SIZE
];
3088 for (i
= 0; i
< table
->rows
; ++i
) {
3089 mono_metadata_decode_row (table
, i
, data
, MONO_EVENT_SIZE
);
3091 if (data
[MONO_EVENT_FLAGS
] & INVALID_EVENT_FLAGS_BITS
)
3092 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i
, data
[MONO_EVENT_FLAGS
]));
3094 if (!is_valid_non_empty_string (ctx
, data
[MONO_EVENT_NAME
]))
3095 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Event row %d Name field %08x", i
, data
[MONO_EVENT_NAME
]));
3097 if (!is_valid_coded_index (ctx
, TYPEDEF_OR_REF_DESC
, data
[MONO_EVENT_TYPE
]))
3098 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Event row %d EventType field %08x", i
, data
[MONO_EVENT_TYPE
]));
3103 verify_event_table_full (VerifyContext
*ctx
)
3105 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_EVENT
];
3106 MonoTableInfo
*sema_table
= &ctx
->image
->tables
[MONO_TABLE_METHODSEMANTICS
];
3107 guint32 data
[MONO_EVENT_SIZE
], sema_data
[MONO_METHOD_SEMA_SIZE
], token
;
3108 gboolean found_add
, found_remove
;
3111 for (i
= 0; i
< table
->rows
; ++i
) {
3112 mono_metadata_decode_row (table
, i
, data
, MONO_EVENT_SIZE
);
3114 token
= make_coded_token (HAS_SEMANTICS_DESC
, MONO_TABLE_EVENT
, i
);
3115 idx
= search_sorted_table (ctx
, MONO_TABLE_METHODSEMANTICS
, MONO_METHOD_SEMA_ASSOCIATION
, token
);
3117 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i
));
3119 //first we move to the first row for this event
3121 if (mono_metadata_decode_row_col (sema_table
, idx
- 1, MONO_METHOD_SEMA_ASSOCIATION
) != token
)
3125 //now move forward looking for AddOn and RemoveOn rows
3126 found_add
= found_remove
= FALSE
;
3127 while (idx
< sema_table
->rows
) {
3128 mono_metadata_decode_row (sema_table
, idx
, sema_data
, MONO_METHOD_SEMA_SIZE
);
3129 if (sema_data
[MONO_METHOD_SEMA_ASSOCIATION
] != token
)
3131 if (sema_data
[MONO_METHOD_SEMA_SEMANTICS
] & METHOD_SEMANTIC_ADD_ON
)
3133 if (sema_data
[MONO_METHOD_SEMA_SEMANTICS
] & METHOD_SEMANTIC_REMOVE_ON
)
3134 found_remove
= TRUE
;
3135 if (found_add
&& found_remove
)
3141 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i
));
3143 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i
));
3148 verify_propertymap_table (VerifyContext
*ctx
)
3150 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_PROPERTYMAP
];
3151 guint32 data
[MONO_PROPERTY_MAP_SIZE
], propertylist
= 0;
3154 for (i
= 0; i
< table
->rows
; ++i
) {
3155 mono_metadata_decode_row (table
, i
, data
, MONO_PROPERTY_MAP_SIZE
);
3157 if (!data
[MONO_PROPERTY_MAP_PARENT
] || data
[MONO_PROPERTY_MAP_PARENT
] > ctx
->image
->tables
[MONO_TABLE_TYPEDEF
].rows
+ 1)
3158 ADD_ERROR (ctx
, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i
, data
[MONO_PROPERTY_MAP_PARENT
]));
3160 if (!data
[MONO_PROPERTY_MAP_PROPERTY_LIST
] || data
[MONO_PROPERTY_MAP_PROPERTY_LIST
] <= propertylist
)
3161 ADD_ERROR (ctx
, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i
, data
[MONO_PROPERTY_MAP_PROPERTY_LIST
]));
3163 propertylist
= data
[MONO_PROPERTY_MAP_PROPERTY_LIST
];
3167 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3169 verify_property_table (VerifyContext
*ctx
)
3171 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_PROPERTY
];
3172 guint32 data
[MONO_PROPERTY_SIZE
];
3175 for (i
= 0; i
< table
->rows
; ++i
) {
3176 mono_metadata_decode_row (table
, i
, data
, MONO_PROPERTY_SIZE
);
3178 if (data
[MONO_PROPERTY_FLAGS
] & INVALID_PROPERTY_FLAGS_BITS
)
3179 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i
, data
[MONO_PROPERTY_FLAGS
]));
3181 if (!is_valid_non_empty_string (ctx
, data
[MONO_PROPERTY_NAME
]))
3182 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Property row %d Name field %08x", i
, data
[MONO_PROPERTY_NAME
]));
3184 if (!is_valid_property_sig_blob (ctx
, data
[MONO_PROPERTY_TYPE
]))
3185 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Property row %d Type field %08x", i
, data
[MONO_PROPERTY_TYPE
]));
3187 if ((data
[MONO_PROPERTY_FLAGS
] & PROPERTY_ATTRIBUTE_HAS_DEFAULT
) &&
3188 search_sorted_table (ctx
, MONO_TABLE_CONSTANT
, MONO_CONSTANT_PARENT
, make_coded_token (HAS_CONSTANT_DESC
, MONO_TABLE_PROPERTY
, i
)) == -1)
3189 ADD_ERROR (ctx
, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i
));
3195 verify_methodimpl_table (VerifyContext
*ctx
)
3197 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_METHODIMPL
];
3198 guint32 data
[MONO_METHODIMPL_SIZE
];
3201 for (i
= 0; i
< table
->rows
; ++i
) {
3202 mono_metadata_decode_row (table
, i
, data
, MONO_METHODIMPL_SIZE
);
3204 if (!data
[MONO_METHODIMPL_CLASS
] || data
[MONO_METHODIMPL_CLASS
] > ctx
->image
->tables
[MONO_TABLE_TYPEDEF
].rows
+ 1)
3205 ADD_ERROR (ctx
, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i
, data
[MONO_TABLE_TYPEDEF
]));
3207 if (!get_coded_index_token (METHODDEF_OR_REF_DESC
, data
[MONO_METHODIMPL_BODY
]))
3208 ADD_ERROR (ctx
, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i
, data
[MONO_METHODIMPL_BODY
]));
3210 if (!is_valid_coded_index (ctx
, METHODDEF_OR_REF_DESC
, data
[MONO_METHODIMPL_BODY
]))
3211 ADD_ERROR (ctx
, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i
, data
[MONO_METHODIMPL_BODY
]));
3213 if (!get_coded_index_token (METHODDEF_OR_REF_DESC
, data
[MONO_METHODIMPL_DECLARATION
]))
3214 ADD_ERROR (ctx
, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i
, data
[MONO_METHODIMPL_DECLARATION
]));
3216 if (!is_valid_coded_index (ctx
, METHODDEF_OR_REF_DESC
, data
[MONO_METHODIMPL_DECLARATION
]))
3217 ADD_ERROR (ctx
, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i
, data
[MONO_METHODIMPL_DECLARATION
]));
3222 verify_moduleref_table (VerifyContext
*ctx
)
3224 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_MODULEREF
];
3225 guint32 data
[MONO_MODULEREF_SIZE
];
3228 for (i
= 0; i
< table
->rows
; ++i
) {
3229 mono_metadata_decode_row (table
, i
, data
, MONO_MODULEREF_SIZE
);
3231 if (!is_valid_non_empty_string (ctx
, data
[MONO_MODULEREF_NAME
]))
3232 ADD_ERROR (ctx
, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i
, data
[MONO_TABLE_TYPEDEF
]));
3237 verify_typespec_table (VerifyContext
*ctx
)
3239 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_TYPESPEC
];
3240 guint32 data
[MONO_TYPESPEC_SIZE
];
3243 for (i
= 0; i
< table
->rows
; ++i
) {
3244 mono_metadata_decode_row (table
, i
, data
, MONO_TYPESPEC_SIZE
);
3246 if (data
[MONO_TYPESPEC_SIGNATURE
] && !is_valid_blob_object (ctx
, data
[MONO_TYPESPEC_SIGNATURE
], 1))
3247 ADD_ERROR (ctx
, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i
, data
[MONO_TYPESPEC_SIGNATURE
]));
3252 verify_typespec_table_full (VerifyContext
*ctx
)
3254 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_TYPESPEC
];
3255 guint32 data
[MONO_TYPESPEC_SIZE
];
3258 for (i
= 0; i
< table
->rows
; ++i
) {
3259 mono_metadata_decode_row (table
, i
, data
, MONO_TYPESPEC_SIZE
);
3260 ctx
->token
= (i
+ 1) | MONO_TOKEN_TYPE_SPEC
;
3261 if (!is_valid_typespec_blob (ctx
, data
[MONO_TYPESPEC_SIGNATURE
]))
3262 ADD_ERROR (ctx
, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i
, data
[MONO_TYPESPEC_SIGNATURE
]));
3267 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
3269 verify_implmap_table (VerifyContext
*ctx
)
3271 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_IMPLMAP
];
3272 guint32 data
[MONO_IMPLMAP_SIZE
], cconv
;
3275 for (i
= 0; i
< table
->rows
; ++i
) {
3276 mono_metadata_decode_row (table
, i
, data
, MONO_IMPLMAP_SIZE
);
3278 if (data
[MONO_IMPLMAP_FLAGS
] & INVALID_IMPLMAP_FLAGS_BITS
)
3279 ADD_ERROR (ctx
, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i
, data
[MONO_IMPLMAP_FLAGS
]));
3281 cconv
= data
[MONO_IMPLMAP_FLAGS
] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK
;
3282 if (cconv
== 0 || cconv
== 0x0600 || cconv
== 0x0700)
3283 ADD_ERROR (ctx
, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i
, cconv
));
3285 if (!is_valid_coded_index (ctx
, MEMBER_FORWARDED_DESC
, data
[MONO_IMPLMAP_MEMBER
]))
3286 ADD_ERROR (ctx
, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i
, data
[MONO_IMPLMAP_MEMBER
]));
3288 if (get_coded_index_table (MEMBER_FORWARDED_DESC
, data
[MONO_IMPLMAP_MEMBER
]) != MONO_TABLE_METHOD
)
3289 ADD_ERROR (ctx
, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i
, data
[MONO_IMPLMAP_MEMBER
]));
3291 if (!get_coded_index_token (MEMBER_FORWARDED_DESC
, data
[MONO_IMPLMAP_MEMBER
]))
3292 ADD_ERROR (ctx
, g_strdup_printf ("Invalid ImplMap row %d null token", i
));
3294 if (!is_valid_non_empty_string (ctx
, data
[MONO_IMPLMAP_NAME
]))
3295 ADD_ERROR (ctx
, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i
, data
[MONO_IMPLMAP_NAME
]));
3297 if (!data
[MONO_IMPLMAP_SCOPE
] || data
[MONO_IMPLMAP_SCOPE
] > ctx
->image
->tables
[MONO_TABLE_MODULEREF
].rows
+ 1)
3298 ADD_ERROR (ctx
, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i
, data
[MONO_IMPLMAP_SCOPE
]));
3303 verify_fieldrva_table (VerifyContext
*ctx
)
3305 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_FIELDRVA
];
3306 guint32 data
[MONO_FIELD_RVA_SIZE
];
3309 for (i
= 0; i
< table
->rows
; ++i
) {
3310 mono_metadata_decode_row (table
, i
, data
, MONO_FIELD_RVA_SIZE
);
3312 if (!data
[MONO_FIELD_RVA_RVA
] || mono_cli_rva_image_map (ctx
->image
, data
[MONO_FIELD_RVA_RVA
]) == INVALID_ADDRESS
)
3313 ADD_ERROR (ctx
, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i
, data
[MONO_FIELD_RVA_RVA
]));
3315 if (!data
[MONO_FIELD_RVA_FIELD
] || data
[MONO_FIELD_RVA_FIELD
] > ctx
->image
->tables
[MONO_TABLE_FIELD
].rows
+ 1)
3316 ADD_ERROR (ctx
, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i
, data
[MONO_FIELD_RVA_FIELD
]));
3320 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
3322 verify_assembly_table (VerifyContext
*ctx
)
3324 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_ASSEMBLY
];
3325 guint32 data
[MONO_ASSEMBLY_SIZE
], hash
;
3328 if (table
->rows
> 1)
3329 ADD_ERROR (ctx
, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table
->rows
));
3331 for (i
= 0; i
< table
->rows
; ++i
) {
3332 mono_metadata_decode_row (table
, i
, data
, MONO_ASSEMBLY_SIZE
);
3334 hash
= data
[MONO_ASSEMBLY_HASH_ALG
];
3335 if (!(hash
== 0 || hash
== 0x8003 || hash
== 0x8004))
3336 ADD_ERROR (ctx
, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i
, hash
));
3338 if (data
[MONO_ASSEMBLY_FLAGS
] & INVALID_ASSEMBLY_FLAGS_BITS
)
3339 ADD_ERROR (ctx
, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i
, data
[MONO_ASSEMBLY_FLAGS
]));
3341 if (data
[MONO_ASSEMBLY_PUBLIC_KEY
] && !is_valid_blob_object (ctx
, data
[MONO_ASSEMBLY_PUBLIC_KEY
], 1))
3342 ADD_ERROR (ctx
, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i
, data
[MONO_ASSEMBLY_FLAGS
]));
3344 if (!is_valid_non_empty_string (ctx
, data
[MONO_ASSEMBLY_NAME
]))
3345 ADD_ERROR (ctx
, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i
, data
[MONO_ASSEMBLY_NAME
]));
3347 if (data
[MONO_ASSEMBLY_CULTURE
] && !is_valid_string (ctx
, data
[MONO_ASSEMBLY_CULTURE
]))
3348 ADD_ERROR (ctx
, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i
, data
[MONO_ASSEMBLY_CULTURE
]));
3352 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
3354 verify_assemblyref_table (VerifyContext
*ctx
)
3356 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_ASSEMBLYREF
];
3357 guint32 data
[MONO_ASSEMBLYREF_SIZE
];
3360 for (i
= 0; i
< table
->rows
; ++i
) {
3361 mono_metadata_decode_row (table
, i
, data
, MONO_ASSEMBLYREF_SIZE
);
3363 if (data
[MONO_ASSEMBLYREF_FLAGS
] & INVALID_ASSEMBLYREF_FLAGS_BITS
)
3364 ADD_ERROR (ctx
, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i
, data
[MONO_ASSEMBLYREF_FLAGS
]));
3366 if (data
[MONO_ASSEMBLYREF_PUBLIC_KEY
] && !is_valid_blob_object (ctx
, data
[MONO_ASSEMBLYREF_PUBLIC_KEY
], 1))
3367 ADD_ERROR (ctx
, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i
, data
[MONO_ASSEMBLYREF_PUBLIC_KEY
]));
3369 if (!is_valid_non_empty_string (ctx
, data
[MONO_ASSEMBLYREF_NAME
]))
3370 ADD_ERROR (ctx
, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i
, data
[MONO_ASSEMBLYREF_NAME
]));
3372 if (data
[MONO_ASSEMBLYREF_CULTURE
] && !is_valid_string (ctx
, data
[MONO_ASSEMBLYREF_CULTURE
]))
3373 ADD_ERROR (ctx
, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i
, data
[MONO_ASSEMBLYREF_CULTURE
]));
3375 if (data
[MONO_ASSEMBLYREF_HASH_VALUE
] && !is_valid_blob_object (ctx
, data
[MONO_ASSEMBLYREF_HASH_VALUE
], 1))
3376 ADD_ERROR (ctx
, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i
, data
[MONO_ASSEMBLYREF_HASH_VALUE
]));
3380 #define INVALID_FILE_FLAGS_BITS ~(1)
3382 verify_file_table (VerifyContext
*ctx
)
3384 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_FILE
];
3385 guint32 data
[MONO_FILE_SIZE
];
3388 for (i
= 0; i
< table
->rows
; ++i
) {
3389 mono_metadata_decode_row (table
, i
, data
, MONO_FILE_SIZE
);
3391 if (data
[MONO_FILE_FLAGS
] & INVALID_FILE_FLAGS_BITS
)
3392 ADD_ERROR (ctx
, g_strdup_printf ("File table row %d has invalid Flags %08x", i
, data
[MONO_FILE_FLAGS
]));
3394 if (!is_valid_non_empty_string (ctx
, data
[MONO_FILE_NAME
]))
3395 ADD_ERROR (ctx
, g_strdup_printf ("File table row %d has invalid Name %08x", i
, data
[MONO_FILE_NAME
]));
3397 if (!data
[MONO_FILE_HASH_VALUE
] || !is_valid_blob_object (ctx
, data
[MONO_FILE_HASH_VALUE
], 1))
3398 ADD_ERROR (ctx
, g_strdup_printf ("File table row %d has invalid HashValue %08x", i
, data
[MONO_FILE_HASH_VALUE
]));
3402 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3404 verify_exportedtype_table (VerifyContext
*ctx
)
3406 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_EXPORTEDTYPE
];
3407 guint32 data
[MONO_EXP_TYPE_SIZE
];
3410 for (i
= 0; i
< table
->rows
; ++i
) {
3411 mono_metadata_decode_row (table
, i
, data
, MONO_EXP_TYPE_SIZE
);
3413 if (data
[MONO_EXP_TYPE_FLAGS
] & INVALID_EXPORTED_TYPE_FLAGS_BITS
)
3414 ADD_ERROR (ctx
, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i
, data
[MONO_EXP_TYPE_FLAGS
]));
3416 if (!is_valid_non_empty_string (ctx
, data
[MONO_EXP_TYPE_NAME
]))
3417 ADD_ERROR (ctx
, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i
, data
[MONO_FILE_NAME
]));
3419 if (data
[MONO_EXP_TYPE_NAMESPACE
] && !is_valid_string (ctx
, data
[MONO_EXP_TYPE_NAMESPACE
]))
3420 ADD_ERROR (ctx
, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i
, data
[MONO_EXP_TYPE_NAMESPACE
]));
3422 if (!is_valid_coded_index (ctx
, IMPLEMENTATION_DESC
, data
[MONO_EXP_TYPE_IMPLEMENTATION
]))
3423 ADD_ERROR (ctx
, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i
, data
[MONO_EXP_TYPE_IMPLEMENTATION
]));
3425 if (!get_coded_index_token (IMPLEMENTATION_DESC
, data
[MONO_EXP_TYPE_IMPLEMENTATION
]))
3426 ADD_ERROR (ctx
, g_strdup_printf ("ExportedType table row %d has null Implementation token", i
));
3428 /*nested type can't have a namespace*/
3429 if (get_coded_index_table (IMPLEMENTATION_DESC
, data
[MONO_EXP_TYPE_IMPLEMENTATION
]) == MONO_TABLE_EXPORTEDTYPE
&& data
[MONO_EXP_TYPE_NAMESPACE
])
3430 ADD_ERROR (ctx
, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i
));
3434 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3436 verify_manifest_resource_table (VerifyContext
*ctx
)
3438 MonoCLIImageInfo
*iinfo
= ctx
->image
->image_info
;
3439 MonoCLIHeader
*ch
= &iinfo
->cli_cli_header
;
3440 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_MANIFESTRESOURCE
];
3441 guint32 data
[MONO_MANIFEST_SIZE
], impl_table
, token
, resources_size
;
3444 resources_size
= ch
->ch_resources
.size
;
3446 for (i
= 0; i
< table
->rows
; ++i
) {
3447 mono_metadata_decode_row (table
, i
, data
, MONO_MANIFEST_SIZE
);
3449 if (data
[MONO_MANIFEST_FLAGS
] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS
)
3450 ADD_ERROR (ctx
, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i
, data
[MONO_MANIFEST_FLAGS
]));
3452 if (data
[MONO_MANIFEST_FLAGS
] != 1 && data
[MONO_MANIFEST_FLAGS
] != 2)
3453 ADD_ERROR (ctx
, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i
, data
[MONO_MANIFEST_FLAGS
]));
3455 if (!is_valid_non_empty_string (ctx
, data
[MONO_MANIFEST_NAME
]))
3456 ADD_ERROR (ctx
, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i
, data
[MONO_MANIFEST_NAME
]));
3458 if (!is_valid_coded_index (ctx
, IMPLEMENTATION_DESC
, data
[MONO_MANIFEST_IMPLEMENTATION
]))
3459 ADD_ERROR (ctx
, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i
, data
[MONO_MANIFEST_IMPLEMENTATION
]));
3461 impl_table
= get_coded_index_table (IMPLEMENTATION_DESC
, data
[MONO_MANIFEST_IMPLEMENTATION
]);
3462 token
= get_coded_index_token (IMPLEMENTATION_DESC
, data
[MONO_MANIFEST_IMPLEMENTATION
]);
3464 if (impl_table
== MONO_TABLE_EXPORTEDTYPE
)
3465 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
])));
3467 if (impl_table
== MONO_TABLE_FILE
&& token
&& data
[MONO_MANIFEST_OFFSET
])
3468 ADD_ERROR (ctx
, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i
));
3470 if (!token
&& data
[MONO_MANIFEST_OFFSET
] >= resources_size
)
3471 ADD_ERROR (ctx
, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i
, data
[MONO_MANIFEST_OFFSET
]));
3476 verify_nested_class_table (VerifyContext
*ctx
)
3478 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_NESTEDCLASS
];
3479 guint32 data
[MONO_NESTED_CLASS_SIZE
];
3482 for (i
= 0; i
< table
->rows
; ++i
) {
3483 mono_metadata_decode_row (table
, i
, data
, MONO_NESTED_CLASS_SIZE
);
3485 if (!data
[MONO_NESTED_CLASS_NESTED
] || data
[MONO_NESTED_CLASS_NESTED
] > ctx
->image
->tables
[MONO_TABLE_TYPEDEF
].rows
)
3486 ADD_ERROR (ctx
, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i
, data
[MONO_NESTED_CLASS_NESTED
]));
3487 if (!data
[MONO_NESTED_CLASS_ENCLOSING
] || data
[MONO_NESTED_CLASS_ENCLOSING
] > ctx
->image
->tables
[MONO_TABLE_TYPEDEF
].rows
)
3488 ADD_ERROR (ctx
, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i
, data
[MONO_NESTED_CLASS_ENCLOSING
]));
3489 if (data
[MONO_NESTED_CLASS_ENCLOSING
] == data
[MONO_NESTED_CLASS_NESTED
])
3490 ADD_ERROR (ctx
, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i
, data
[MONO_NESTED_CLASS_ENCLOSING
]));
3494 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3496 verify_generic_param_table (VerifyContext
*ctx
)
3498 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_GENERICPARAM
];
3499 guint32 data
[MONO_GENERICPARAM_SIZE
], token
, last_token
= 0;
3500 int i
, param_number
= 0;
3502 for (i
= 0; i
< table
->rows
; ++i
) {
3503 mono_metadata_decode_row (table
, i
, data
, MONO_GENERICPARAM_SIZE
);
3505 if (data
[MONO_GENERICPARAM_FLAGS
] & INVALID_GENERIC_PARAM_FLAGS_BITS
)
3506 ADD_ERROR (ctx
, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i
, data
[MONO_GENERICPARAM_FLAGS
]));
3508 if ((data
[MONO_GENERICPARAM_FLAGS
] & MONO_GEN_PARAM_VARIANCE_MASK
) == 0x3)
3509 ADD_ERROR (ctx
, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i
));
3511 if (!is_valid_non_empty_string (ctx
, data
[MONO_GENERICPARAM_NAME
]))
3512 ADD_ERROR (ctx
, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i
, data
[MONO_GENERICPARAM_NAME
]));
3514 token
= data
[MONO_GENERICPARAM_OWNER
];
3516 if (!is_valid_coded_index (ctx
, TYPE_OR_METHODDEF_DESC
, token
))
3517 ADD_ERROR (ctx
, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i
, token
));
3519 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC
, token
))
3520 ADD_ERROR (ctx
, g_strdup_printf ("GenericParam table row %d has null Owner token", i
));
3522 if (token
!= last_token
) {
3527 if (data
[MONO_GENERICPARAM_NUMBER
] != param_number
)
3528 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
));
3535 verify_method_spec_table (VerifyContext
*ctx
)
3537 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_METHODSPEC
];
3538 guint32 data
[MONO_METHODSPEC_SIZE
];
3541 for (i
= 0; i
< table
->rows
; ++i
) {
3542 mono_metadata_decode_row (table
, i
, data
, MONO_METHODSPEC_SIZE
);
3544 if (!is_valid_coded_index (ctx
, METHODDEF_OR_REF_DESC
, data
[MONO_METHODSPEC_METHOD
]))
3545 ADD_ERROR (ctx
, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i
, data
[MONO_METHODSPEC_METHOD
]));
3547 if (!get_coded_index_token (METHODDEF_OR_REF_DESC
, data
[MONO_METHODSPEC_METHOD
]))
3548 ADD_ERROR (ctx
, g_strdup_printf ("MethodSpec table row %d has null Method token", i
));
3550 if (data
[MONO_METHODSPEC_SIGNATURE
] && !is_valid_blob_object (ctx
, data
[MONO_METHODSPEC_SIGNATURE
], 1))
3551 ADD_ERROR (ctx
, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i
, data
[MONO_METHODSPEC_SIGNATURE
]));
3556 verify_method_spec_table_full (VerifyContext
*ctx
)
3558 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_METHODSPEC
];
3559 guint32 data
[MONO_METHODSPEC_SIZE
];
3562 for (i
= 0; i
< table
->rows
; ++i
) {
3563 mono_metadata_decode_row (table
, i
, data
, MONO_METHODSPEC_SIZE
);
3565 if (!is_valid_methodspec_blob (ctx
, data
[MONO_METHODSPEC_SIGNATURE
]))
3566 ADD_ERROR (ctx
, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i
, data
[MONO_METHODSPEC_SIGNATURE
]));
3571 verify_generic_param_constraint_table (VerifyContext
*ctx
)
3573 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_GENERICPARAMCONSTRAINT
];
3574 guint32 data
[MONO_GENPARCONSTRAINT_SIZE
];
3577 for (i
= 0; i
< table
->rows
; ++i
) {
3578 mono_metadata_decode_row (table
, i
, data
, MONO_GENPARCONSTRAINT_SIZE
);
3580 if (!data
[MONO_GENPARCONSTRAINT_GENERICPAR
] || data
[MONO_GENPARCONSTRAINT_GENERICPAR
] > ctx
->image
->tables
[MONO_TABLE_GENERICPARAM
].rows
)
3581 ADD_ERROR (ctx
, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i
, data
[MONO_TABLE_GENERICPARAM
]));
3583 if (!is_valid_coded_index (ctx
, TYPEDEF_OR_REF_DESC
, data
[MONO_GENPARCONSTRAINT_CONSTRAINT
]))
3584 ADD_ERROR (ctx
, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i
, data
[MONO_GENPARCONSTRAINT_CONSTRAINT
]));
3586 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC
, data
[MONO_GENPARCONSTRAINT_CONSTRAINT
]))
3587 ADD_ERROR (ctx
, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i
));
3594 const char *name_space
;
3595 guint32 resolution_scope
;
3599 typedef_hash (gconstpointer _key
)
3601 const TypeDefUniqueId
*key
= _key
;
3602 return g_str_hash (key
->name
) ^ g_str_hash (key
->name_space
) ^ key
->resolution_scope
; /*XXX better salt the int key*/
3606 typedef_equals (gconstpointer _a
, gconstpointer _b
)
3608 const TypeDefUniqueId
*a
= _a
;
3609 const TypeDefUniqueId
*b
= _b
;
3610 return !strcmp (a
->name
, b
->name
) && !strcmp (a
->name_space
, b
->name_space
) && a
->resolution_scope
== b
->resolution_scope
;
3614 verify_typedef_table_global_constraints (VerifyContext
*ctx
)
3617 guint32 data
[MONO_TYPEDEF_SIZE
];
3618 guint32 nested_data
[MONO_NESTED_CLASS_SIZE
];
3619 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_TYPEDEF
];
3620 MonoTableInfo
*nested_table
= &ctx
->image
->tables
[MONO_TABLE_NESTEDCLASS
];
3621 GHashTable
*unique_types
= g_hash_table_new_full (&typedef_hash
, &typedef_equals
, g_free
, NULL
);
3623 for (i
= 0; i
< table
->rows
; ++i
) {
3625 TypeDefUniqueId
*type
= g_new (TypeDefUniqueId
, 1);
3626 mono_metadata_decode_row (table
, i
, data
, MONO_TYPEDEF_SIZE
);
3628 type
->name
= mono_metadata_string_heap (ctx
->image
, data
[MONO_TYPEDEF_NAME
]);
3629 type
->name_space
= mono_metadata_string_heap (ctx
->image
, data
[MONO_TYPEDEF_NAMESPACE
]);
3630 type
->resolution_scope
= 0;
3632 visibility
= data
[MONO_TYPEDEF_FLAGS
] & TYPE_ATTRIBUTE_VISIBILITY_MASK
;
3633 if (visibility
>= TYPE_ATTRIBUTE_NESTED_PUBLIC
&& visibility
<= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM
) {
3634 int res
= search_sorted_table (ctx
, MONO_TABLE_NESTEDCLASS
, MONO_NESTED_CLASS_NESTED
, i
+ 1);
3635 g_assert (res
>= 0);
3637 mono_metadata_decode_row (nested_table
, res
, nested_data
, MONO_NESTED_CLASS_SIZE
);
3638 type
->resolution_scope
= nested_data
[MONO_NESTED_CLASS_ENCLOSING
];
3641 if (g_hash_table_lookup (unique_types
, type
)) {
3642 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
));
3643 g_hash_table_destroy (unique_types
);
3647 g_hash_table_insert (unique_types
, type
, GUINT_TO_POINTER (1));
3650 g_hash_table_destroy (unique_types
);
3654 verify_typeref_table_global_constraints (VerifyContext
*ctx
)
3657 guint32 data
[MONO_TYPEREF_SIZE
];
3658 MonoTableInfo
*table
= &ctx
->image
->tables
[MONO_TABLE_TYPEREF
];
3659 GHashTable
*unique_types
= g_hash_table_new_full (&typedef_hash
, &typedef_equals
, g_free
, NULL
);
3661 for (i
= 0; i
< table
->rows
; ++i
) {
3662 TypeDefUniqueId
*type
= g_new (TypeDefUniqueId
, 1);
3663 mono_metadata_decode_row (table
, i
, data
, MONO_TYPEREF_SIZE
);
3665 type
->resolution_scope
= data
[MONO_TYPEREF_SCOPE
];
3666 type
->name
= mono_metadata_string_heap (ctx
->image
, data
[MONO_TYPEREF_NAME
]);
3667 type
->name_space
= mono_metadata_string_heap (ctx
->image
, data
[MONO_TYPEREF_NAMESPACE
]);
3669 if (g_hash_table_lookup (unique_types
, type
)) {
3670 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
));
3671 g_hash_table_destroy (unique_types
);
3675 g_hash_table_insert (unique_types
, type
, GUINT_TO_POINTER (1));
3678 g_hash_table_destroy (unique_types
);
3682 verify_tables_data_global_constraints (VerifyContext
*ctx
)
3684 verify_typeref_table_global_constraints (ctx
);
3686 verify_typedef_table_global_constraints (ctx
);
3690 verify_tables_data (VerifyContext
*ctx
)
3692 OffsetAndSize tables_area
= get_metadata_stream (ctx
, &ctx
->image
->heap_tables
);
3693 guint32 size
= 0, tables_offset
;
3696 for (i
= 0; i
< 0x2D; ++i
) {
3697 MonoTableInfo
*table
= &ctx
->image
->tables
[i
];
3699 tmp_size
= size
+ (guint32
)table
->row_size
* (guint32
)table
->rows
;
3700 if (tmp_size
< size
) {
3708 ADD_ERROR (ctx
, g_strdup_printf ("table space is either empty or overflowed"));
3710 tables_offset
= ctx
->image
->tables_base
- ctx
->data
;
3711 if (!bounds_check_offset (&tables_area
, tables_offset
, size
))
3712 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
)));
3714 verify_module_table (ctx
);
3716 verify_typeref_table (ctx
);
3718 verify_typedef_table (ctx
);
3720 verify_field_table (ctx
);
3722 verify_method_table (ctx
);
3724 verify_param_table (ctx
);
3726 verify_interfaceimpl_table (ctx
);
3728 verify_memberref_table (ctx
);
3730 verify_constant_table (ctx
);
3732 verify_cattr_table (ctx
);
3734 verify_field_marshal_table (ctx
);
3736 verify_decl_security_table (ctx
);
3738 verify_class_layout_table (ctx
);
3740 verify_field_layout_table (ctx
);
3742 verify_standalonesig_table (ctx
);
3744 verify_eventmap_table (ctx
);
3746 verify_event_table (ctx
);
3748 verify_propertymap_table (ctx
);
3750 verify_property_table (ctx
);
3752 verify_methodimpl_table (ctx
);
3754 verify_moduleref_table (ctx
);
3756 verify_typespec_table (ctx
);
3758 verify_implmap_table (ctx
);
3760 verify_fieldrva_table (ctx
);
3762 verify_assembly_table (ctx
);
3764 verify_assemblyref_table (ctx
);
3766 verify_file_table (ctx
);
3768 verify_exportedtype_table (ctx
);
3770 verify_manifest_resource_table (ctx
);
3772 verify_nested_class_table (ctx
);
3774 verify_generic_param_table (ctx
);
3776 verify_method_spec_table (ctx
);
3778 verify_generic_param_constraint_table (ctx
);
3780 verify_tables_data_global_constraints (ctx
);
3784 init_verify_context (VerifyContext
*ctx
, MonoImage
*image
, GSList
**error_list
)
3786 memset (ctx
, 0, sizeof (VerifyContext
));
3788 ctx
->report_error
= error_list
!= NULL
;
3789 ctx
->report_warning
= FALSE
; //export this setting in the API
3791 ctx
->size
= image
->raw_data_len
;
3792 ctx
->data
= image
->raw_data
;
3796 cleanup_context (VerifyContext
*ctx
, GSList
**error_list
)
3798 g_free (ctx
->sections
);
3800 *error_list
= ctx
->errors
;
3802 mono_free_verify_list (ctx
->errors
);
3807 mono_verifier_verify_pe_data (MonoImage
*image
, GSList
**error_list
)
3811 if (!mono_verifier_is_enabled_for_image (image
))
3814 init_verify_context (&ctx
, image
, error_list
);
3815 ctx
.stage
= STAGE_PE
;
3817 verify_msdos_header (&ctx
);
3819 verify_pe_header (&ctx
);
3821 verify_pe_optional_header (&ctx
);
3823 load_section_table (&ctx
);
3825 load_data_directories (&ctx
);
3827 verify_import_table (&ctx
);
3829 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3830 verify_resources_table (&ctx
);
3833 return cleanup_context (&ctx
, error_list
);
3837 mono_verifier_verify_cli_data (MonoImage
*image
, GSList
**error_list
)
3841 if (!mono_verifier_is_enabled_for_image (image
))
3844 init_verify_context (&ctx
, image
, error_list
);
3845 ctx
.stage
= STAGE_CLI
;
3847 verify_cli_header (&ctx
);
3849 verify_metadata_header (&ctx
);
3851 verify_tables_schema (&ctx
);
3854 return cleanup_context (&ctx
, error_list
);
3859 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3860 * Other verification checks are meant to be done lazily by the runtime. Those include:
3861 * blob items (signatures, method headers, custom attributes, etc)
3862 * type semantics related
3864 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3866 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3867 * operation still need more checking.
3870 mono_verifier_verify_table_data (MonoImage
*image
, GSList
**error_list
)
3874 if (!mono_verifier_is_enabled_for_image (image
))
3877 init_verify_context (&ctx
, image
, error_list
);
3878 ctx
.stage
= STAGE_TABLES
;
3880 verify_tables_data (&ctx
);
3882 return cleanup_context (&ctx
, error_list
);
3887 * Verifies all other constraints.
3890 mono_verifier_verify_full_table_data (MonoImage
*image
, GSList
**error_list
)
3894 if (!mono_verifier_is_enabled_for_image (image
))
3897 init_verify_context (&ctx
, image
, error_list
);
3898 ctx
.stage
= STAGE_TABLES
;
3900 verify_typedef_table_full (&ctx
);
3902 verify_field_table_full (&ctx
);
3904 verify_method_table_full (&ctx
);
3906 verify_memberref_table_full (&ctx
);
3908 verify_cattr_table_full (&ctx
);
3910 verify_field_marshal_table_full (&ctx
);
3912 verify_decl_security_table_full (&ctx
);
3914 verify_standalonesig_table_full (&ctx
);
3916 verify_event_table_full (&ctx
);
3918 verify_typespec_table_full (&ctx
);
3920 verify_method_spec_table_full (&ctx
);
3923 return cleanup_context (&ctx
, error_list
);
3927 mono_verifier_verify_field_signature (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
3931 if (!mono_verifier_is_enabled_for_image (image
))
3934 init_verify_context (&ctx
, image
, error_list
);
3935 ctx
.stage
= STAGE_TABLES
;
3937 is_valid_field_signature (&ctx
, offset
);
3938 return cleanup_context (&ctx
, error_list
);
3942 mono_verifier_verify_method_header (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
3946 if (!mono_verifier_is_enabled_for_image (image
))
3949 init_verify_context (&ctx
, image
, error_list
);
3950 ctx
.stage
= STAGE_TABLES
;
3952 is_valid_method_header (&ctx
, offset
);
3953 return cleanup_context (&ctx
, error_list
);
3957 mono_verifier_verify_method_signature (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
3961 if (!mono_verifier_is_enabled_for_image (image
))
3964 init_verify_context (&ctx
, image
, error_list
);
3965 ctx
.stage
= STAGE_TABLES
;
3967 is_valid_method_signature (&ctx
, offset
);
3968 return cleanup_context (&ctx
, error_list
);
3972 mono_verifier_verify_memberref_signature (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
3976 if (!mono_verifier_is_enabled_for_image (image
))
3979 init_verify_context (&ctx
, image
, error_list
);
3980 ctx
.stage
= STAGE_TABLES
;
3982 is_valid_method_or_field_signature (&ctx
, offset
);
3983 return cleanup_context (&ctx
, error_list
);
3987 mono_verifier_verify_standalone_signature (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
3991 if (!mono_verifier_is_enabled_for_image (image
))
3994 init_verify_context (&ctx
, image
, error_list
);
3995 ctx
.stage
= STAGE_TABLES
;
3997 is_valid_standalonesig_blob (&ctx
, offset
);
3998 return cleanup_context (&ctx
, error_list
);
4002 mono_verifier_verify_typespec_signature (MonoImage
*image
, guint32 offset
, guint32 token
, GSList
**error_list
)
4006 if (!mono_verifier_is_enabled_for_image (image
))
4009 init_verify_context (&ctx
, image
, error_list
);
4010 ctx
.stage
= STAGE_TABLES
;
4013 is_valid_typespec_blob (&ctx
, offset
);
4014 return cleanup_context (&ctx
, error_list
);
4018 mono_verifier_verify_methodspec_signature (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
4022 if (!mono_verifier_is_enabled_for_image (image
))
4025 init_verify_context (&ctx
, image
, error_list
);
4026 ctx
.stage
= STAGE_TABLES
;
4028 is_valid_methodspec_blob (&ctx
, offset
);
4029 return cleanup_context (&ctx
, error_list
);
4033 verify_user_string (VerifyContext
*ctx
, guint32 offset
)
4035 OffsetAndSize heap_us
= get_metadata_stream (ctx
, &ctx
->image
->heap_us
);
4036 guint32 entry_size
, bytes
;
4038 if (heap_us
.size
< offset
)
4039 ADD_ERROR (ctx
, g_strdup ("User string offset beyond heap_us size"));
4041 if (!decode_value (ctx
->data
+ offset
+ heap_us
.offset
, heap_us
.size
- heap_us
.offset
, &entry_size
, &bytes
))
4042 ADD_ERROR (ctx
, g_strdup ("Could not decode user string blob size"));
4044 if (CHECK_ADD4_OVERFLOW_UN (entry_size
, bytes
))
4045 ADD_ERROR (ctx
, g_strdup ("User string size overflow"));
4047 entry_size
+= bytes
;
4049 if (ADD_IS_GREATER_OR_OVF (offset
, entry_size
, heap_us
.size
))
4050 ADD_ERROR (ctx
, g_strdup ("User string oveflow heap_us"));
4054 mono_verifier_verify_string_signature (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
4058 if (!mono_verifier_is_enabled_for_image (image
))
4061 init_verify_context (&ctx
, image
, error_list
);
4062 ctx
.stage
= STAGE_TABLES
;
4064 verify_user_string (&ctx
, offset
);
4066 return cleanup_context (&ctx
, error_list
);
4070 mono_verifier_verify_cattr_blob (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
4074 if (!mono_verifier_is_enabled_for_image (image
))
4077 init_verify_context (&ctx
, image
, error_list
);
4078 ctx
.stage
= STAGE_TABLES
;
4080 is_valid_cattr_blob (&ctx
, offset
);
4082 return cleanup_context (&ctx
, error_list
);
4086 mono_verifier_verify_cattr_content (MonoImage
*image
, MonoMethod
*ctor
, const guchar
*data
, guint32 size
, GSList
**error_list
)
4090 if (!mono_verifier_is_enabled_for_image (image
))
4093 init_verify_context (&ctx
, image
, error_list
);
4094 ctx
.stage
= STAGE_TABLES
;
4096 is_valid_cattr_content (&ctx
, ctor
, (const char*)data
, size
);
4098 return cleanup_context (&ctx
, error_list
);
4102 mono_verifier_is_sig_compatible (MonoImage
*image
, MonoMethod
*method
, MonoMethodSignature
*signature
)
4104 MonoMethodSignature
*original_sig
;
4105 if (!mono_verifier_is_enabled_for_image (image
))
4108 original_sig
= mono_method_signature (method
);
4109 if (original_sig
->call_convention
== MONO_CALL_VARARG
) {
4110 if (original_sig
->hasthis
!= signature
->hasthis
)
4112 if (original_sig
->call_convention
!= signature
->call_convention
)
4114 if (original_sig
->explicit_this
!= signature
->explicit_this
)
4116 if (original_sig
->call_convention
!= signature
->call_convention
)
4118 if (original_sig
->pinvoke
!= signature
->pinvoke
)
4120 if (original_sig
->sentinelpos
!= signature
->sentinelpos
)
4122 } else if (!mono_metadata_signature_equal (signature
, original_sig
)) {
4131 mono_verifier_verify_table_data (MonoImage
*image
, GSList
**error_list
)
4137 mono_verifier_verify_cli_data (MonoImage
*image
, GSList
**error_list
)
4143 mono_verifier_verify_pe_data (MonoImage
*image
, GSList
**error_list
)
4149 mono_verifier_verify_full_table_data (MonoImage
*image
, GSList
**error_list
)
4155 mono_verifier_verify_field_signature (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
4161 mono_verifier_verify_method_header (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
4167 mono_verifier_verify_method_signature (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
4173 mono_verifier_verify_memberref_signature (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
4179 mono_verifier_verify_standalone_signature (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
4185 mono_verifier_verify_typespec_signature (MonoImage
*image
, guint32 offset
, guint32 token
, GSList
**error_list
)
4191 mono_verifier_verify_methodspec_signature (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
4197 mono_verifier_verify_string_signature (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
4203 mono_verifier_verify_cattr_blob (MonoImage
*image
, guint32 offset
, GSList
**error_list
)
4209 mono_verifier_verify_cattr_content (MonoImage
*image
, MonoMethod
*ctor
, const guchar
*data
, guint32 size
, GSList
**error_list
)
4215 mono_verifier_is_sig_compatible (MonoImage
*image
, MonoMethod
*method
, MonoMethodSignature
*signature
)
4221 #endif /* DISABLE_VERIFIER */