2010-04-19 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / metadata-verify.c
blob78a7a533d6489a8ad12a27d8c91addc7e521e069
1 /*
2 * metadata-verify.c: Metadata verfication support
4 * Author:
5 * Mono Project (http://www.mono-project.com)
7 * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
8 */
9 #include <mono/metadata/object-internals.h>
10 #include <mono/metadata/verify.h>
11 #include <mono/metadata/verify-internals.h>
12 #include <mono/metadata/opcodes.h>
13 #include <mono/metadata/tabledefs.h>
14 #include <mono/metadata/reflection.h>
15 #include <mono/metadata/debug-helpers.h>
16 #include <mono/metadata/mono-endian.h>
17 #include <mono/metadata/metadata.h>
18 #include <mono/metadata/metadata-internals.h>
19 #include <mono/metadata/class-internals.h>
20 #include <mono/metadata/tokentype.h>
21 #include <mono/metadata/security-manager.h>
22 #include <mono/metadata/security-core-clr.h>
23 #include <mono/metadata/cil-coff.h>
24 #include <mono/metadata/attrdefs.h>
25 #include <mono/utils/strenc.h>
26 #include <string.h>
27 //#include <signal.h>
28 #include <ctype.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)
50 #else
51 #define VERIFIER_DEBUG(code)
52 #endif
54 #define INVALID_OFFSET ((guint32)-1)
55 #define INVALID_ADDRESS 0xffffffff
57 enum {
58 STAGE_PE,
59 STAGE_CLI,
60 STAGE_TABLES
63 enum {
64 IMPORT_TABLE_IDX = 1,
65 RESOURCE_TABLE_IDX = 2,
66 CERTIFICATE_TABLE_IDX = 4,
67 RELOCATION_TABLE_IDX = 5,
68 IAT_IDX = 12,
69 CLI_HEADER_IDX = 14,
72 enum {
73 STRINGS_STREAM,
74 USER_STRINGS_STREAM,
75 BLOB_STREAM,
76 GUID_STREAM,
77 TILDE_STREAM
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)
85 2, /*bits*/
86 3, /*tables*/
87 MONO_TABLE_TYPEDEF,
88 MONO_TABLE_TYPEREF,
89 MONO_TABLE_TYPESPEC,
91 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
92 2, /*bits*/
93 3, /*tables*/
94 MONO_TABLE_FIELD,
95 MONO_TABLE_PARAM,
96 MONO_TABLE_PROPERTY,
98 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
99 5, /*bits*/
100 20, /*tables*/
101 MONO_TABLE_METHOD,
102 MONO_TABLE_FIELD,
103 MONO_TABLE_TYPEREF,
104 MONO_TABLE_TYPEDEF,
105 MONO_TABLE_PARAM,
106 MONO_TABLE_INTERFACEIMPL,
107 MONO_TABLE_MEMBERREF,
108 MONO_TABLE_MODULE,
109 MONO_TABLE_DECLSECURITY,
110 MONO_TABLE_PROPERTY,
111 MONO_TABLE_EVENT,
112 MONO_TABLE_STANDALONESIG,
113 MONO_TABLE_MODULEREF,
114 MONO_TABLE_TYPESPEC,
115 MONO_TABLE_ASSEMBLY,
116 MONO_TABLE_ASSEMBLYREF,
117 MONO_TABLE_FILE,
118 MONO_TABLE_EXPORTEDTYPE,
119 MONO_TABLE_MANIFESTRESOURCE,
120 MONO_TABLE_GENERICPARAM,
122 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
123 1, /*bits*/
124 2, /*tables*/
125 MONO_TABLE_FIELD,
126 MONO_TABLE_PARAM,
128 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
129 2, /*bits*/
130 3, /*tables*/
131 MONO_TABLE_TYPEDEF,
132 MONO_TABLE_METHOD,
133 MONO_TABLE_ASSEMBLY,
135 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
136 3, /*bits*/
137 5, /*tables*/
138 MONO_TABLE_TYPEDEF,
139 MONO_TABLE_TYPEREF,
140 MONO_TABLE_MODULE,
141 MONO_TABLE_METHOD,
142 MONO_TABLE_TYPESPEC,
144 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
145 1, /*bits*/
146 2, /*tables*/
147 MONO_TABLE_EVENT,
148 MONO_TABLE_PROPERTY,
150 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
151 1, /*bits*/
152 2, /*tables*/
153 MONO_TABLE_METHOD,
154 MONO_TABLE_MEMBERREF,
156 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
157 1, /*bits*/
158 2, /*tables*/
159 MONO_TABLE_FIELD,
160 MONO_TABLE_METHOD,
162 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
163 2, /*bits*/
164 3, /*tables*/
165 MONO_TABLE_FILE,
166 MONO_TABLE_ASSEMBLYREF,
167 MONO_TABLE_EXPORTEDTYPE,
169 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
170 3, /*bits*/
171 5, /*tables*/
172 INVALID_TABLE,
173 INVALID_TABLE,
174 MONO_TABLE_METHOD,
175 MONO_TABLE_MEMBERREF,
176 INVALID_TABLE,
178 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
179 2, /*bits*/
180 4, /*tables*/
181 MONO_TABLE_MODULE,
182 MONO_TABLE_MODULEREF,
183 MONO_TABLE_ASSEMBLYREF,
184 MONO_TABLE_TYPEREF,
186 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
187 1, /*bits*/
188 2, /*tables*/
189 MONO_TABLE_TYPEDEF,
190 MONO_TABLE_METHOD
193 typedef struct {
194 guint32 rva;
195 guint32 size;
196 guint32 translated_offset;
197 } DataDirectory;
199 typedef struct {
200 guint32 offset;
201 guint32 size;
202 } OffsetAndSize;
204 typedef struct {
205 guint32 baseRVA;
206 guint32 baseOffset;
207 guint32 size;
208 guint32 rellocationsRVA;
209 guint16 numberOfRelocations;
210 } SectionHeader;
212 typedef struct {
213 guint32 row_count;
214 guint32 row_size;
215 guint32 offset;
216 } TableInfo;
218 typedef struct {
219 const char *data;
220 guint32 size, token;
221 GSList *errors;
222 int valid;
223 MonoImage *image;
224 gboolean report_error;
225 gboolean report_warning;
226 int stage;
228 DataDirectory data_directories [16];
229 guint32 section_count;
230 SectionHeader *sections;
232 OffsetAndSize metadata_streams [5]; //offset from begin of the image
233 } VerifyContext;
235 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
236 do { \
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); \
242 } while (0)
244 #define ADD_WARNING(__ctx, __msg) \
245 do { \
246 if ((__ctx)->report_warning) { \
247 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
248 (__ctx)->valid = 0; \
249 return; \
251 } while (0)
253 #define ADD_ERROR_NO_RETURN(__ctx, __msg) \
254 do { \
255 if ((__ctx)->report_error) \
256 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
257 (__ctx)->valid = 0; \
258 } while (0)
260 #define ADD_ERROR(__ctx, __msg) \
261 do { \
262 if ((__ctx)->report_error) \
263 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
264 (__ctx)->valid = 0; \
265 return; \
266 } while (0)
268 #define FAIL(__ctx, __msg) \
269 do { \
270 if ((__ctx)->report_error) \
271 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
272 (__ctx)->valid = 0; \
273 return FALSE; \
274 } while (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)
285 #else
286 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
287 #endif
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))
292 static const char *
293 dword_align (const char *ptr)
295 #if SIZEOF_VOID_P == 8
296 return (const char *) (((guint64) (ptr + 3)) & ~3);
297 #else
298 return (const char *) (((guint32) (ptr + 3)) & ~3);
299 #endif
302 static guint32
303 pe_signature_offset (VerifyContext *ctx)
305 return read32 (ctx->data + 0x3c);
308 static guint32
309 pe_header_offset (VerifyContext *ctx)
311 return read32 (ctx->data + 0x3c) + 4;
314 static gboolean
315 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
317 int i;
319 if (rva + size < rva) //overflow
320 return FALSE;
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;
326 int i;
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)
333 return TRUE;
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;
340 tables++;
342 return FALSE;
345 if (!ctx->sections)
346 return FALSE;
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)
352 return TRUE;
354 return FALSE;
357 static gboolean
358 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
360 if (dir->translated_offset > offset)
361 return FALSE;
362 if (dir->size < size)
363 return FALSE;
364 return offset + size <= dir->translated_offset + dir->size;
367 static gboolean
368 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
370 if (off->offset > offset)
371 return FALSE;
373 if (off->size < size)
374 return FALSE;
376 return offset + size <= off->offset + off->size;
379 static guint32
380 translate_rva (VerifyContext *ctx, guint32 rva)
382 int i;
384 if (ctx->stage > STAGE_PE)
385 return mono_cli_rva_image_map (ctx->image, rva);
387 if (!ctx->sections)
388 return FALSE;
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;
395 /* double check */
396 return res >= ctx->size ? INVALID_OFFSET : res;
400 return INVALID_OFFSET;
403 static void
404 verify_msdos_header (VerifyContext *ctx)
406 guint32 lfanew;
407 if (ctx->size < 128)
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"));
416 static void
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"));
423 pe_header += 4;
424 offset += 4;
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"));
432 static void
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);
441 offset += 20;
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)));
464 } else {
465 if (read16 (pe_optional_header) == 0x20B)
466 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
467 else
468 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
472 static void
473 load_section_table (VerifyContext *ctx)
475 int i;
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+*/
482 ptr += 244;
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);
494 ptr += 40;
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));
522 ptr += 40;
526 static gboolean
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;
533 static void
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;
538 int i;
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) {
546 ptr += 8;
547 continue;
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);
559 ptr += 8;
563 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
565 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
567 static void
568 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
570 const char *ptr;
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));
592 static void
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);
602 if (it.size < 40)
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);
614 if (iat_rva) {
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));
622 if (name_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));
635 if (ilt_rva) {
636 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
637 CHECK_ERROR ();
640 if (iat_rva)
641 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
644 static void
645 verify_resources_table (VerifyContext *ctx)
647 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
648 guint32 offset;
649 guint16 named_entries, id_entries;
650 const char *ptr, *root, *end;
652 if (it.rva == 0)
653 return;
655 if (it.size < 16)
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---*/
678 static DataDirectory
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;
683 DataDirectory res;
685 entry += idx;
686 res.rva = entry->rva;
687 res.size = entry->size;
688 res.translated_offset = translate_rva (ctx, res.rva);
689 return res;
692 static void
693 verify_cli_header (VerifyContext *ctx)
695 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
696 guint32 offset;
697 const char *ptr;
698 int i;
700 if (it.rva == 0)
701 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
703 if (it.size != 72)
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"));
724 ptr += 24;
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));
732 ptr += 8;
734 if (rva && i > 1)
735 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
739 static guint32
740 pad4 (guint32 offset)
742 if (offset & 0x3) //pad to the next 4 byte boundary
743 offset = (offset & ~0x3) + 4;
744 return offset;
747 static void
748 verify_metadata_header (VerifyContext *ctx)
750 int i;
751 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
752 guint32 offset, section_count;
753 const char *ptr;
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
760 ptr += 8;
761 it.rva = read32 (ptr);
762 ptr += 4;
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);
769 if (it.size < 20)
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"));
786 ptr += 4;
787 offset += 4;
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));
802 ptr += 8;
803 offset += 8;
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])
809 break;
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;
825 else {
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;
829 continue;
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"));
851 static void
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;
858 guint32 count;
859 int i;
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]));
866 if (ptr [5] != 0)
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);
873 count = 0;
874 for (i = 0; i < 64; ++i) {
875 if (!(valid_tables & ((guint64)1 << i)))
876 continue;
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));
885 ++count;
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));
890 ptr += 24;
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));
897 ptr += 4;
902 /*----------nothing from here on can use data_directory or metadata_streams ---*/
904 static guint32
905 get_col_offset (VerifyContext *ctx, int table, int column)
907 guint32 bitfield = ctx->image->tables [table].size_bitfield;
908 guint32 offset = 0;
910 while (column-- > 0)
911 offset += mono_metadata_table_size (bitfield, column);
913 return offset;
916 static guint32
917 get_col_size (VerifyContext *ctx, int table, int column)
919 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
922 static OffsetAndSize
923 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
925 OffsetAndSize res;
926 res.offset = header->data - ctx->data;
927 res.size = header->size;
929 return res;
932 static gboolean
933 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
935 OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
936 glong length;
937 const char *data = ctx->data + strings.offset;
939 if (offset >= strings.size)
940 return FALSE;
941 if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing
942 return FALSE;
944 if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
945 return FALSE;
946 return allow_empty || length > 0;
949 static gboolean
950 is_valid_string (VerifyContext *ctx, guint32 offset)
952 return is_valid_string_full (ctx, offset, TRUE);
955 static gboolean
956 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
958 return is_valid_string_full (ctx, offset, FALSE);
961 static gboolean
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;
968 static guint32
969 get_coded_index_token (int token_kind, guint32 coded_token)
971 guint32 bits = coded_index_desc [token_kind];
972 return coded_token >> bits;
975 static guint32
976 get_coded_index_table (int kind, guint32 coded_token)
978 guint32 idx, bits = coded_index_desc [kind];
979 kind += 2;
980 idx = coded_token & ((1 << bits) - 1);
981 return coded_index_desc [kind + idx];
984 static guint32
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++];
989 guint32 i;
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 ();
995 return -1;
998 static gboolean
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)
1007 return FALSE;
1009 /*token_kind points to the first table idx*/
1010 table = coded_index_desc [token_kind + table];
1012 if (table == INVALID_TABLE)
1013 return FALSE;
1014 return token <= ctx->image->tables [table].rows;
1017 typedef struct {
1018 guint32 token;
1019 guint32 col_size;
1020 guint32 col_offset;
1021 MonoTableInfo *table;
1022 } RowLocator;
1024 static int
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;
1035 static int
1036 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1038 MonoTableInfo *tinfo = &ctx->image->tables [table];
1039 RowLocator locator;
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;
1046 base = tinfo->base;
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);
1050 if (!res)
1051 return -1;
1053 return (res - base) / tinfo->row_size;
1056 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1057 static const char*
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*/
1064 static int
1065 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1067 if (offset == 0)
1068 return strcmp (str, "");
1070 return strcmp (str, get_string_ptr (ctx, offset));
1073 static gboolean
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);
1082 static gboolean
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]);
1088 static gboolean
1089 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1091 unsigned char b;
1092 const unsigned char *ptr = (const unsigned char *)_ptr;
1094 if (!available)
1095 return FALSE;
1097 b = *ptr;
1098 *value = *size = 0;
1100 if ((b & 0x80) == 0) {
1101 *size = 1;
1102 *value = b;
1103 } else if ((b & 0x40) == 0) {
1104 if (available < 2)
1105 return FALSE;
1106 *size = 2;
1107 *value = ((b & 0x3f) << 8 | ptr [1]);
1108 } else {
1109 if (available < 4)
1110 return FALSE;
1111 *size = 4;
1112 *value = ((b & 0x1f) << 24) |
1113 (ptr [1] << 16) |
1114 (ptr [2] << 8) |
1115 ptr [3];
1118 return TRUE;
1121 static gboolean
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)
1128 return FALSE;
1130 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1131 return FALSE;
1133 if (CHECK_ADD4_OVERFLOW_UN (offset, enc_size))
1134 return FALSE;
1136 offset += enc_size;
1138 if (ADD_IS_GREATER_OR_OVF (offset, value, blob.size))
1139 return FALSE;
1141 *size = value;
1142 *first_byte = blob.data + offset;
1143 return TRUE;
1146 static gboolean
1147 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1149 const char *ptr = *_ptr;
1150 if (ptr + size > limit)
1151 return FALSE;
1152 switch (size) {
1153 case 1:
1154 *dest = *((guint8*)ptr);
1155 ++ptr;
1156 break;
1157 case 2:
1158 *dest = read16 (ptr);
1159 ptr += 2;
1160 break;
1161 case 4:
1162 *dest = read32 (ptr);
1163 ptr += 4;
1164 break;
1166 *_ptr = ptr;
1167 return TRUE;
1170 static gboolean
1171 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1173 unsigned size = 0;
1174 const char *ptr = *_ptr;
1175 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1176 *_ptr = ptr + size;
1177 return res;
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)
1185 static gboolean
1186 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1188 static gboolean
1189 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1191 static gboolean
1192 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1194 const char *ptr = *_ptr;
1195 unsigned type = 0;
1196 unsigned token = 0;
1198 while (TRUE) {
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) {
1203 --ptr;
1204 break;
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));
1214 *_ptr = ptr;
1215 return TRUE;
1218 static gboolean
1219 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1221 const char *ptr = *_ptr;
1222 unsigned val = 0;
1223 unsigned size, num, i;
1225 if (!safe_read8 (val, ptr, end))
1226 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1228 if (val == 0)
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));
1247 *_ptr = ptr;
1248 return TRUE;
1251 static gboolean
1252 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1254 const char *ptr = *_ptr;
1255 unsigned type;
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));
1270 if (ctx->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"));
1279 if (count == 0)
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));
1286 *_ptr = ptr;
1287 return TRUE;
1290 static gboolean
1291 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1293 const char *ptr = *_ptr;
1294 unsigned type;
1295 unsigned token = 0;
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));
1306 switch (type) {
1307 case MONO_TYPE_PTR:
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) {
1315 --ptr;
1316 if (!parse_type (ctx, &ptr, end))
1317 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1319 break;
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));
1328 if (ctx->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));
1333 break;
1335 case MONO_TYPE_VAR:
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"));
1339 break;
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"));
1346 break;
1348 case MONO_TYPE_GENERICINST:
1349 if (!parse_generic_inst (ctx, &ptr, end))
1350 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1351 break;
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"));
1356 break;
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"));
1363 break;
1365 *_ptr = ptr;
1366 return TRUE;
1369 static gboolean
1370 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1372 const char *ptr;
1373 unsigned type = 0;
1375 if (!parse_custom_mods (ctx, _ptr, end))
1376 return FALSE;
1378 ptr = *_ptr;
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) {
1383 *_ptr = ptr;
1384 return TRUE;
1387 //it's a byref, update the cursor ptr
1388 if (type == MONO_TYPE_BYREF)
1389 *_ptr = ptr;
1391 return parse_type (ctx, _ptr, end);
1394 static gboolean
1395 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1397 const char *ptr;
1398 unsigned type = 0;
1400 if (!parse_custom_mods (ctx, _ptr, end))
1401 return FALSE;
1403 ptr = *_ptr;
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) {
1408 *_ptr = ptr;
1409 return TRUE;
1412 //it's a byref, update the cursor ptr
1413 if (type == MONO_TYPE_BYREF)
1414 *_ptr = ptr;
1416 return parse_type (ctx, _ptr, end);
1419 static gboolean
1420 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1422 unsigned cconv = 0;
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"));
1430 if (cconv & 0x80)
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"));
1463 if (saw_sentinel)
1464 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1466 saw_sentinel = TRUE;
1467 } else {
1468 --ptr;
1472 if (!parse_param (ctx, &ptr, end))
1473 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1476 *_ptr = ptr;
1477 return TRUE;
1480 static gboolean
1481 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1483 unsigned sig = 0;
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))
1497 return FALSE;
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));
1507 *_ptr = ptr;
1508 return TRUE;
1511 static gboolean
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))
1524 return FALSE;
1526 if (safe_read8 (signature, ptr, end)) {
1527 if (signature != MONO_TYPE_BYREF)
1528 --ptr;
1530 *_ptr = ptr;
1532 return parse_type (ctx, _ptr, end);
1535 static gboolean
1536 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1538 unsigned sig = 0;
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"));
1545 if (sig != 0x07)
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)
1575 continue;
1577 --ptr;
1579 if (!parse_type (ctx, &ptr, end))
1580 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1583 *_ptr = ptr;
1584 return TRUE;
1587 static gboolean
1588 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1590 guint32 size = 0;
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"));
1596 end = ptr + size;
1598 if (!safe_read8 (signature, ptr, end))
1599 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1601 if (signature != 6)
1602 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1603 --ptr;
1605 return parse_field (ctx, &ptr, end);
1608 static gboolean
1609 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1611 guint32 size = 0;
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"));
1616 end = ptr + size;
1618 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1621 static gboolean
1622 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1624 guint32 size = 0;
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"));
1630 end = ptr + size;
1632 if (!safe_read8 (signature, ptr, end))
1633 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1634 --ptr;
1636 if (signature == 0x06)
1637 return parse_field (ctx, &ptr, end);
1639 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1642 static gboolean
1643 is_valid_cattr_blob (VerifyContext *ctx, guint32 offset)
1645 guint32 size = 0;
1646 unsigned prolog = 0;
1647 const char *ptr = NULL, *end;
1649 if (!offset)
1650 return TRUE;
1652 if (!decode_signature_header (ctx, offset, &size, &ptr))
1653 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1654 end = ptr + size;
1656 if (!safe_read16 (prolog, ptr, end))
1657 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1659 if (prolog != 1)
1660 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1662 return TRUE;
1665 static gboolean
1666 is_valid_cattr_type (MonoType *type)
1668 MonoClass *klass;
1670 if (type->type == MONO_TYPE_OBJECT || (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_STRING))
1671 return TRUE;
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;
1681 return FALSE;
1684 static gboolean
1685 is_valid_ser_string_full (VerifyContext *ctx, const char **str_start, guint32 *str_len, const char **_ptr, const char *end)
1687 guint32 size = 0;
1688 const char *ptr = *_ptr;
1690 *str_start = NULL;
1691 *str_len = 0;
1693 if (ptr >= end)
1694 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1696 /*NULL string*/
1697 if (*ptr == (char)0xFF) {
1698 *_ptr = ptr + 1;
1699 return TRUE;
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"));
1708 *str_start = ptr;
1709 *str_len = size;
1711 *_ptr = ptr + size;
1712 return TRUE;
1715 static gboolean
1716 is_valid_ser_string (VerifyContext *ctx, const char **_ptr, const char *end)
1718 const char *dummy_str;
1719 guint32 dummy_int;
1720 return is_valid_ser_string_full (ctx, &dummy_str, &dummy_int, _ptr, end);
1723 static MonoClass*
1724 get_enum_by_encoded_name (VerifyContext *ctx, const char **_ptr, const char *end)
1726 MonoType *type;
1727 MonoClass *klass;
1728 const char *str_start = NULL;
1729 const char *ptr = *_ptr;
1730 char *enum_name;
1731 guint32 str_len = 0;
1733 if (!is_valid_ser_string_full (ctx, &str_start, &str_len, &ptr, end))
1734 return NULL;
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"));
1739 return NULL;
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);
1745 if (!type) {
1746 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid enum class %s", enum_name));
1747 g_free (enum_name);
1748 return NULL;
1750 g_free (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));
1755 return NULL;
1758 *_ptr = ptr;
1759 return klass;
1762 static gboolean
1763 is_valid_fixed_param (VerifyContext *ctx, MonoType *mono_type, const char **_ptr, const char *end)
1765 MonoClass *klass;
1766 const char *ptr = *_ptr;
1767 int elem_size = 0;
1768 guint32 element_count, i;
1769 int type;
1771 klass = mono_type->data.klass;
1772 type = mono_type->type;
1774 handle_enum:
1775 switch (type) {
1776 case MONO_TYPE_BOOLEAN:
1777 case MONO_TYPE_I1:
1778 case MONO_TYPE_U1:
1779 elem_size = 1;
1780 break;
1781 case MONO_TYPE_I2:
1782 case MONO_TYPE_U2:
1783 case MONO_TYPE_CHAR:
1784 elem_size = 2;
1785 break;
1786 case MONO_TYPE_I4:
1787 case MONO_TYPE_U4:
1788 case MONO_TYPE_R4:
1789 elem_size = 4;
1790 break;
1791 case MONO_TYPE_I8:
1792 case MONO_TYPE_U8:
1793 case MONO_TYPE_R8:
1794 elem_size = 8;
1795 break;
1797 case MONO_TYPE_STRING:
1798 *_ptr = ptr;
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) {
1807 type = sub_type;
1808 goto handle_enum;
1810 if (sub_type == MONO_TYPE_ENUM) {
1811 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1812 if (!klass)
1813 return FALSE;
1815 klass = klass->element_class;
1816 type = klass->byval_arg.type;
1817 goto handle_enum;
1819 if (sub_type == 0x50) { /*Type*/
1820 *_ptr = ptr;
1821 return is_valid_ser_string (ctx, _ptr, end);
1823 if (sub_type == MONO_TYPE_SZARRAY) {
1824 MonoType simple_type = {{0}};
1825 unsigned etype = 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);
1831 if (!klass)
1832 return FALSE;
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);
1836 } else
1837 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1839 type = MONO_TYPE_SZARRAY;
1840 goto handle_enum;
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));
1849 *_ptr = ptr;
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;
1858 goto handle_enum;
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) {
1867 *_ptr = ptr;
1868 return TRUE;
1870 for (i = 0; i < element_count; ++i) {
1871 if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
1872 return FALSE;
1874 *_ptr = ptr;
1875 return TRUE;
1876 default:
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;
1883 return TRUE;
1886 static gboolean
1887 is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
1889 MonoError error;
1890 unsigned prolog = 0;
1891 const char *end;
1892 MonoMethodSignature *sig;
1893 int args, i;
1894 unsigned num_named;
1896 if (!ctor)
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);
1903 return FALSE;
1906 if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
1907 FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1909 end = ptr + size;
1911 if (!safe_read16 (prolog, ptr, end))
1912 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1914 if (prolog != 1)
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))
1921 return FALSE;
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}};
1929 unsigned kind;
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);
1943 if (!klass)
1944 return FALSE;
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) {
1951 MonoClass *klass;
1952 unsigned etype = 0;
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);
1958 if (!klass)
1959 return FALSE;
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);
1963 } else
1964 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1966 type = &mono_array_class_get (klass, 1)->byval_arg;
1967 } else {
1968 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
1971 if (!is_valid_ser_string (ctx, &ptr, end))
1972 return FALSE;
1974 if (!is_valid_fixed_param (ctx, type, &ptr, end))
1975 return FALSE;
1979 return TRUE;
1982 static gboolean
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;
1990 static gboolean
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;
1998 static gboolean
1999 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
2001 guint32 size = 0;
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"));
2007 end = ptr + size;
2009 if (!safe_read8 (signature, ptr, end))
2010 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2012 --ptr;
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);
2023 static gboolean
2024 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
2026 guint32 size = 0;
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"));
2031 end = ptr + size;
2033 return parse_property_signature (ctx, &ptr, end);
2036 static gboolean
2037 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
2039 guint32 size = 0;
2040 const char *ptr = NULL, *end;
2041 unsigned type = 0;
2043 if (!decode_signature_header (ctx, offset, &size, &ptr))
2044 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
2045 end = ptr + size;
2047 if (!parse_custom_mods (ctx, &ptr, end))
2048 return FALSE;
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)
2061 return TRUE;
2063 --ptr;
2064 return parse_type (ctx, &ptr, end);
2067 static gboolean
2068 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
2070 guint32 size = 0;
2071 const char *ptr = NULL, *end;
2072 unsigned type = 0;
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"));
2077 end = ptr + size;
2079 if (!safe_read8 (type, ptr, end))
2080 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
2082 if (type != 0x0A)
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"));
2088 if (!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));
2095 return TRUE;
2098 static gboolean
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)
2105 return FALSE;
2107 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2108 return FALSE;
2110 if (entry_size < minsize)
2111 return FALSE;
2113 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
2114 return FALSE;
2115 entry_size += bytes;
2117 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
2120 static gboolean
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
2134 offset += 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));
2139 return TRUE;
2142 switch (type) {
2143 case MONO_TYPE_BOOLEAN:
2144 case MONO_TYPE_I1:
2145 case MONO_TYPE_U1:
2146 size = 1;
2147 break;
2148 case MONO_TYPE_CHAR:
2149 case MONO_TYPE_I2:
2150 case MONO_TYPE_U2:
2151 size = 2;
2152 break;
2153 case MONO_TYPE_I4:
2154 case MONO_TYPE_U4:
2155 case MONO_TYPE_R4:
2156 case MONO_TYPE_CLASS:
2157 size = 4;
2158 break;
2160 case MONO_TYPE_I8:
2161 case MONO_TYPE_U8:
2162 case MONO_TYPE_R8:
2163 size = 8;
2164 break;
2165 default:
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));
2172 offset += bytes;
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"));
2179 return TRUE;
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
2186 static gboolean
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) {
2204 case 0:
2205 case 1:
2206 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
2207 case 2:
2208 header >>= 2;
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)));
2211 return TRUE;
2213 //FAT HEADER
2214 --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;
2219 if (size != 3)
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))
2245 return TRUE;
2247 ptr += code_size;
2249 do {
2250 unsigned section_header = 0, section_size = 0;
2251 gboolean is_fat;
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))
2297 break;
2298 } while (1);
2299 return TRUE;
2302 static void
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]));
2326 static void
2327 verify_typeref_table (VerifyContext *ctx)
2329 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2330 guint32 data [MONO_TYPEREF_SIZE];
2331 int i;
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)
2351 static void
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;
2357 int i;
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];
2416 static void
2417 verify_typedef_table_full (VerifyContext *ctx)
2419 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2420 guint32 data [MONO_TYPEDEF_SIZE];
2421 int i;
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);
2429 if (i == 0) {
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"));
2434 continue;
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));
2440 } else {
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;
2444 if (is_sys_obj) {
2445 if (has_parent)
2446 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2447 } else {
2448 if (!has_parent) {
2449 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2456 /*bits 3,11,14 */
2457 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2458 static void
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;
2463 int i;
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));
2524 static void
2525 verify_field_table_full (VerifyContext *ctx)
2527 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2528 guint32 data [MONO_FIELD_SIZE];
2529 int i;
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))
2541 static void
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;
2548 const char *name;
2549 int i;
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));
2569 if (access == 0x7)
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
2635 if (rva) {
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));
2640 } else {
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)) {
2646 if (rva)
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];
2674 static void
2675 verify_method_table_full (VerifyContext *ctx)
2677 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2678 guint32 data [MONO_METHOD_SIZE], rva;
2679 int i;
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));
2693 static guint32
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;
2708 ++row;
2711 /*no more methods, all params apply to the last one*/
2712 *current_method = table->rows;
2713 return (guint32)-1;
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))
2718 static void
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;
2724 int i;
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"));
2729 return;
2732 remaining_params = get_next_param_count (ctx, &current_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));
2744 } else {
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, &current_method);
2762 first_param = TRUE;
2767 static void
2768 verify_interfaceimpl_table (VerifyContext *ctx)
2770 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2771 guint32 data [MONO_INTERFACEIMPL_SIZE];
2772 int i;
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));
2787 static void
2788 verify_memberref_table (VerifyContext *ctx)
2790 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2791 guint32 data [MONO_MEMBERREF_SIZE];
2792 int i;
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]));
2812 static void
2813 verify_memberref_table_full (VerifyContext *ctx)
2815 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2816 guint32 data [MONO_MEMBERREF_SIZE];
2817 int i;
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]));
2827 static void
2828 verify_constant_table (VerifyContext *ctx)
2830 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2831 guint32 data [MONO_CONSTANT_SIZE], type;
2832 int i;
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]));
2852 static void
2853 verify_cattr_table (VerifyContext *ctx)
2855 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2856 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2857 int i;
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]));
2873 static void
2874 verify_cattr_table_full (VerifyContext *ctx)
2876 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2877 MonoMethod *ctor;
2878 const char *ptr;
2879 guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2880 int i;
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;
2892 break;
2893 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2894 mtoken |= MONO_TOKEN_MEMBER_REF;
2895 break;
2896 default:
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]));
2910 static void
2911 verify_field_marshal_table (VerifyContext *ctx)
2913 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2914 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2915 int i;
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]));
2934 static void
2935 verify_field_marshal_table_full (VerifyContext *ctx)
2937 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2938 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2939 int i;
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]));
2949 static void
2950 verify_decl_security_table (VerifyContext *ctx)
2952 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2953 guint32 data [MONO_DECL_SECURITY_SIZE];
2954 int i;
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));
2970 static void
2971 verify_decl_security_table_full (VerifyContext *ctx)
2973 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2974 guint32 data [MONO_DECL_SECURITY_SIZE];
2975 int i;
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]));
2985 static void
2986 verify_class_layout_table (VerifyContext *ctx)
2988 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2989 guint32 data [MONO_CLASS_LAYOUT_SIZE];
2990 int i;
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]) {
2999 case 0:
3000 case 1:
3001 case 2:
3002 case 4:
3003 case 8:
3004 case 16:
3005 case 32:
3006 case 64:
3007 case 128:
3008 break;
3009 default:
3010 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3015 static void
3016 verify_field_layout_table (VerifyContext *ctx)
3018 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3019 guint32 data [MONO_FIELD_LAYOUT_SIZE];
3020 int i;
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]));
3030 static void
3031 verify_standalonesig_table (VerifyContext *ctx)
3033 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3034 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3035 int i;
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]));
3045 static void
3046 verify_standalonesig_table_full (VerifyContext *ctx)
3048 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3049 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3050 int i;
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]));
3060 static void
3061 verify_eventmap_table (VerifyContext *ctx)
3063 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3064 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3065 int i;
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))
3081 static void
3082 verify_event_table (VerifyContext *ctx)
3084 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3085 guint32 data [MONO_EVENT_SIZE];
3086 int i;
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]));
3102 static void
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;
3109 int i, idx;
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);
3116 if (idx == -1)
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
3120 while (idx > 0) {
3121 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3122 break;
3123 --idx;
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)
3130 break;
3131 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3132 found_add = TRUE;
3133 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3134 found_remove = TRUE;
3135 if (found_add && found_remove)
3136 break;
3137 ++idx;
3140 if (!found_add)
3141 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3142 if (!found_remove)
3143 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3147 static void
3148 verify_propertymap_table (VerifyContext *ctx)
3150 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3151 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3152 int i;
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))
3168 static void
3169 verify_property_table (VerifyContext *ctx)
3171 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3172 guint32 data [MONO_PROPERTY_SIZE];
3173 int i;
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));
3194 static void
3195 verify_methodimpl_table (VerifyContext *ctx)
3197 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3198 guint32 data [MONO_METHODIMPL_SIZE];
3199 int i;
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]));
3221 static void
3222 verify_moduleref_table (VerifyContext *ctx)
3224 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3225 guint32 data [MONO_MODULEREF_SIZE];
3226 int i;
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]));
3236 static void
3237 verify_typespec_table (VerifyContext *ctx)
3239 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3240 guint32 data [MONO_TYPESPEC_SIZE];
3241 int i;
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]));
3251 static void
3252 verify_typespec_table_full (VerifyContext *ctx)
3254 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3255 guint32 data [MONO_TYPESPEC_SIZE];
3256 int i;
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]));
3264 ctx->token = 0;
3267 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
3268 static void
3269 verify_implmap_table (VerifyContext *ctx)
3271 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3272 guint32 data [MONO_IMPLMAP_SIZE], cconv;
3273 int i;
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]));
3302 static void
3303 verify_fieldrva_table (VerifyContext *ctx)
3305 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3306 guint32 data [MONO_FIELD_RVA_SIZE];
3307 int i;
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))
3321 static void
3322 verify_assembly_table (VerifyContext *ctx)
3324 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3325 guint32 data [MONO_ASSEMBLY_SIZE], hash;
3326 int i;
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)
3353 static void
3354 verify_assemblyref_table (VerifyContext *ctx)
3356 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3357 guint32 data [MONO_ASSEMBLYREF_SIZE];
3358 int i;
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)
3381 static void
3382 verify_file_table (VerifyContext *ctx)
3384 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3385 guint32 data [MONO_FILE_SIZE];
3386 int i;
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)
3403 static void
3404 verify_exportedtype_table (VerifyContext *ctx)
3406 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3407 guint32 data [MONO_EXP_TYPE_SIZE];
3408 int i;
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))
3435 static void
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;
3442 int i;
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]));
3475 static void
3476 verify_nested_class_table (VerifyContext *ctx)
3478 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3479 guint32 data [MONO_NESTED_CLASS_SIZE];
3480 int i;
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))
3495 static void
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) {
3523 param_number = 0;
3524 last_token = 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));
3530 ++param_number;
3534 static void
3535 verify_method_spec_table (VerifyContext *ctx)
3537 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3538 guint32 data [MONO_METHODSPEC_SIZE];
3539 int i;
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]));
3555 static void
3556 verify_method_spec_table_full (VerifyContext *ctx)
3558 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3559 guint32 data [MONO_METHODSPEC_SIZE];
3560 int i;
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]));
3570 static void
3571 verify_generic_param_constraint_table (VerifyContext *ctx)
3573 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3574 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3575 int i;
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));
3592 typedef struct {
3593 const char *name;
3594 const char *name_space;
3595 guint32 resolution_scope;
3596 } TypeDefUniqueId;
3598 static guint
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*/
3605 static gboolean
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;
3613 static void
3614 verify_typedef_table_global_constraints (VerifyContext *ctx)
3616 int i;
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) {
3624 guint visibility;
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);
3644 g_free (type);
3645 return;
3647 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3650 g_hash_table_destroy (unique_types);
3653 static void
3654 verify_typeref_table_global_constraints (VerifyContext *ctx)
3656 int i;
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);
3672 g_free (type);
3673 return;
3675 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3678 g_hash_table_destroy (unique_types);
3681 static void
3682 verify_tables_data_global_constraints (VerifyContext *ctx)
3684 verify_typeref_table_global_constraints (ctx);
3685 CHECK_ERROR ();
3686 verify_typedef_table_global_constraints (ctx);
3689 static void
3690 verify_tables_data (VerifyContext *ctx)
3692 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3693 guint32 size = 0, tables_offset;
3694 int i;
3696 for (i = 0; i < 0x2D; ++i) {
3697 MonoTableInfo *table = &ctx->image->tables [i];
3698 guint32 tmp_size;
3699 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3700 if (tmp_size < size) {
3701 size = 0;
3702 break;
3704 size = tmp_size;
3707 if (size == 0)
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);
3715 CHECK_ERROR ();
3716 verify_typeref_table (ctx);
3717 CHECK_ERROR ();
3718 verify_typedef_table (ctx);
3719 CHECK_ERROR ();
3720 verify_field_table (ctx);
3721 CHECK_ERROR ();
3722 verify_method_table (ctx);
3723 CHECK_ERROR ();
3724 verify_param_table (ctx);
3725 CHECK_ERROR ();
3726 verify_interfaceimpl_table (ctx);
3727 CHECK_ERROR ();
3728 verify_memberref_table (ctx);
3729 CHECK_ERROR ();
3730 verify_constant_table (ctx);
3731 CHECK_ERROR ();
3732 verify_cattr_table (ctx);
3733 CHECK_ERROR ();
3734 verify_field_marshal_table (ctx);
3735 CHECK_ERROR ();
3736 verify_decl_security_table (ctx);
3737 CHECK_ERROR ();
3738 verify_class_layout_table (ctx);
3739 CHECK_ERROR ();
3740 verify_field_layout_table (ctx);
3741 CHECK_ERROR ();
3742 verify_standalonesig_table (ctx);
3743 CHECK_ERROR ();
3744 verify_eventmap_table (ctx);
3745 CHECK_ERROR ();
3746 verify_event_table (ctx);
3747 CHECK_ERROR ();
3748 verify_propertymap_table (ctx);
3749 CHECK_ERROR ();
3750 verify_property_table (ctx);
3751 CHECK_ERROR ();
3752 verify_methodimpl_table (ctx);
3753 CHECK_ERROR ();
3754 verify_moduleref_table (ctx);
3755 CHECK_ERROR ();
3756 verify_typespec_table (ctx);
3757 CHECK_ERROR ();
3758 verify_implmap_table (ctx);
3759 CHECK_ERROR ();
3760 verify_fieldrva_table (ctx);
3761 CHECK_ERROR ();
3762 verify_assembly_table (ctx);
3763 CHECK_ERROR ();
3764 verify_assemblyref_table (ctx);
3765 CHECK_ERROR ();
3766 verify_file_table (ctx);
3767 CHECK_ERROR ();
3768 verify_exportedtype_table (ctx);
3769 CHECK_ERROR ();
3770 verify_manifest_resource_table (ctx);
3771 CHECK_ERROR ();
3772 verify_nested_class_table (ctx);
3773 CHECK_ERROR ();
3774 verify_generic_param_table (ctx);
3775 CHECK_ERROR ();
3776 verify_method_spec_table (ctx);
3777 CHECK_ERROR ();
3778 verify_generic_param_constraint_table (ctx);
3779 CHECK_ERROR ();
3780 verify_tables_data_global_constraints (ctx);
3783 static void
3784 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
3786 memset (ctx, 0, sizeof (VerifyContext));
3787 ctx->image = image;
3788 ctx->report_error = error_list != NULL;
3789 ctx->report_warning = FALSE; //export this setting in the API
3790 ctx->valid = 1;
3791 ctx->size = image->raw_data_len;
3792 ctx->data = image->raw_data;
3795 static gboolean
3796 cleanup_context (VerifyContext *ctx, GSList **error_list)
3798 g_free (ctx->sections);
3799 if (error_list)
3800 *error_list = ctx->errors;
3801 else
3802 mono_free_verify_list (ctx->errors);
3803 return ctx->valid;
3806 gboolean
3807 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3809 VerifyContext ctx;
3811 if (!mono_verifier_is_enabled_for_image (image))
3812 return TRUE;
3814 init_verify_context (&ctx, image, error_list);
3815 ctx.stage = STAGE_PE;
3817 verify_msdos_header (&ctx);
3818 CHECK_STATE();
3819 verify_pe_header (&ctx);
3820 CHECK_STATE();
3821 verify_pe_optional_header (&ctx);
3822 CHECK_STATE();
3823 load_section_table (&ctx);
3824 CHECK_STATE();
3825 load_data_directories (&ctx);
3826 CHECK_STATE();
3827 verify_import_table (&ctx);
3828 CHECK_STATE();
3829 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3830 verify_resources_table (&ctx);
3832 cleanup:
3833 return cleanup_context (&ctx, error_list);
3836 gboolean
3837 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3839 VerifyContext ctx;
3841 if (!mono_verifier_is_enabled_for_image (image))
3842 return TRUE;
3844 init_verify_context (&ctx, image, error_list);
3845 ctx.stage = STAGE_CLI;
3847 verify_cli_header (&ctx);
3848 CHECK_STATE();
3849 verify_metadata_header (&ctx);
3850 CHECK_STATE();
3851 verify_tables_schema (&ctx);
3853 cleanup:
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
3863 * vtable 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.
3869 gboolean
3870 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3872 VerifyContext ctx;
3874 if (!mono_verifier_is_enabled_for_image (image))
3875 return TRUE;
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.
3889 gboolean
3890 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3892 VerifyContext ctx;
3894 if (!mono_verifier_is_enabled_for_image (image))
3895 return TRUE;
3897 init_verify_context (&ctx, image, error_list);
3898 ctx.stage = STAGE_TABLES;
3900 verify_typedef_table_full (&ctx);
3901 CHECK_STATE ();
3902 verify_field_table_full (&ctx);
3903 CHECK_STATE ();
3904 verify_method_table_full (&ctx);
3905 CHECK_STATE ();
3906 verify_memberref_table_full (&ctx);
3907 CHECK_STATE ();
3908 verify_cattr_table_full (&ctx);
3909 CHECK_STATE ();
3910 verify_field_marshal_table_full (&ctx);
3911 CHECK_STATE ();
3912 verify_decl_security_table_full (&ctx);
3913 CHECK_STATE ();
3914 verify_standalonesig_table_full (&ctx);
3915 CHECK_STATE ();
3916 verify_event_table_full (&ctx);
3917 CHECK_STATE ();
3918 verify_typespec_table_full (&ctx);
3919 CHECK_STATE ();
3920 verify_method_spec_table_full (&ctx);
3922 cleanup:
3923 return cleanup_context (&ctx, error_list);
3926 gboolean
3927 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3929 VerifyContext ctx;
3931 if (!mono_verifier_is_enabled_for_image (image))
3932 return TRUE;
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);
3941 gboolean
3942 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3944 VerifyContext ctx;
3946 if (!mono_verifier_is_enabled_for_image (image))
3947 return TRUE;
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);
3956 gboolean
3957 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3959 VerifyContext ctx;
3961 if (!mono_verifier_is_enabled_for_image (image))
3962 return TRUE;
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);
3971 gboolean
3972 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3974 VerifyContext ctx;
3976 if (!mono_verifier_is_enabled_for_image (image))
3977 return TRUE;
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);
3986 gboolean
3987 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3989 VerifyContext ctx;
3991 if (!mono_verifier_is_enabled_for_image (image))
3992 return TRUE;
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);
4001 gboolean
4002 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4004 VerifyContext ctx;
4006 if (!mono_verifier_is_enabled_for_image (image))
4007 return TRUE;
4009 init_verify_context (&ctx, image, error_list);
4010 ctx.stage = STAGE_TABLES;
4011 ctx.token = token;
4013 is_valid_typespec_blob (&ctx, offset);
4014 return cleanup_context (&ctx, error_list);
4017 gboolean
4018 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4020 VerifyContext ctx;
4022 if (!mono_verifier_is_enabled_for_image (image))
4023 return TRUE;
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);
4032 static void
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"));
4053 gboolean
4054 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4056 VerifyContext ctx;
4058 if (!mono_verifier_is_enabled_for_image (image))
4059 return TRUE;
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);
4069 gboolean
4070 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4072 VerifyContext ctx;
4074 if (!mono_verifier_is_enabled_for_image (image))
4075 return TRUE;
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);
4085 gboolean
4086 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4088 VerifyContext ctx;
4090 if (!mono_verifier_is_enabled_for_image (image))
4091 return TRUE;
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);
4101 gboolean
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))
4106 return TRUE;
4108 original_sig = mono_method_signature (method);
4109 if (original_sig->call_convention == MONO_CALL_VARARG) {
4110 if (original_sig->hasthis != signature->hasthis)
4111 return FALSE;
4112 if (original_sig->call_convention != signature->call_convention)
4113 return FALSE;
4114 if (original_sig->explicit_this != signature->explicit_this)
4115 return FALSE;
4116 if (original_sig->call_convention != signature->call_convention)
4117 return FALSE;
4118 if (original_sig->pinvoke != signature->pinvoke)
4119 return FALSE;
4120 if (original_sig->sentinelpos != signature->sentinelpos)
4121 return FALSE;
4122 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4123 return FALSE;
4126 return TRUE;
4129 #else
4130 gboolean
4131 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4133 return TRUE;
4136 gboolean
4137 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
4139 return TRUE;
4142 gboolean
4143 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
4145 return TRUE;
4148 gboolean
4149 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4151 return TRUE;
4154 gboolean
4155 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4157 return TRUE;
4160 gboolean
4161 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4163 return TRUE;
4166 gboolean
4167 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4169 return TRUE;
4172 gboolean
4173 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
4175 return TRUE;
4178 gboolean
4179 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4181 return TRUE;
4184 gboolean
4185 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4187 return TRUE;
4190 gboolean
4191 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4193 return TRUE;
4196 gboolean
4197 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4199 return TRUE;
4202 gboolean
4203 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4205 return TRUE;
4208 gboolean
4209 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4211 return TRUE;
4214 gboolean
4215 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4217 return TRUE;
4221 #endif /* DISABLE_VERIFIER */