2010-06-20 Jb Evain <jbevain@novell.com>
[mono.git] / mono / metadata / metadata-verify.c
blobe37ef43a0245f8e4ee7bb487bf4ca7532e0b7015
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 < 2)
784 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 2 streams (#~ and #GUID)"));
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"));
848 static void
849 verify_tables_schema (VerifyContext *ctx)
851 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
852 unsigned offset = tables_area.offset;
853 const char *ptr = ctx->data + offset;
854 guint64 valid_tables;
855 guint32 count;
856 int i;
858 if (tables_area.size < 24)
859 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
861 if (ptr [4] != 2 && ptr [4] != 1)
862 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
863 if (ptr [5] != 0)
864 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
866 if ((ptr [6] & ~0x7) != 0)
867 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]));
869 valid_tables = read64 (ptr + 8);
870 count = 0;
871 for (i = 0; i < 64; ++i) {
872 if (!(valid_tables & ((guint64)1 << i)))
873 continue;
875 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
876 Unused: 0x1E 0x1F 0x2D-0x3F
877 We don't care about the MS extensions.*/
878 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
879 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i));
880 if (i == 0x1E || i == 0x1F || i >= 0x2D)
881 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
882 ++count;
885 if (tables_area.size < 24 + count * 4)
886 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));
887 ptr += 24;
889 for (i = 0; i < 64; ++i) {
890 if (valid_tables & ((guint64)1 << i)) {
891 guint32 row_count = read32 (ptr);
892 if (row_count > (1 << 24) - 1)
893 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
894 ptr += 4;
899 /*----------nothing from here on can use data_directory or metadata_streams ---*/
901 static guint32
902 get_col_offset (VerifyContext *ctx, int table, int column)
904 guint32 bitfield = ctx->image->tables [table].size_bitfield;
905 guint32 offset = 0;
907 while (column-- > 0)
908 offset += mono_metadata_table_size (bitfield, column);
910 return offset;
913 static guint32
914 get_col_size (VerifyContext *ctx, int table, int column)
916 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
919 static OffsetAndSize
920 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
922 OffsetAndSize res;
923 res.offset = header->data - ctx->data;
924 res.size = header->size;
926 return res;
929 static gboolean
930 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
932 OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
933 glong length;
934 const char *data = ctx->data + strings.offset;
936 if (offset >= strings.size)
937 return FALSE;
938 if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing
939 return FALSE;
941 if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
942 return FALSE;
943 return allow_empty || length > 0;
946 static gboolean
947 is_valid_string (VerifyContext *ctx, guint32 offset)
949 return is_valid_string_full (ctx, offset, TRUE);
952 static gboolean
953 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
955 return is_valid_string_full (ctx, offset, FALSE);
958 static gboolean
959 is_valid_guid (VerifyContext *ctx, guint32 offset)
961 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
962 return guids.size >= 8 && guids.size - 8 >= offset;
965 static guint32
966 get_coded_index_token (int token_kind, guint32 coded_token)
968 guint32 bits = coded_index_desc [token_kind];
969 return coded_token >> bits;
972 static guint32
973 get_coded_index_table (int kind, guint32 coded_token)
975 guint32 idx, bits = coded_index_desc [kind];
976 kind += 2;
977 idx = coded_token & ((1 << bits) - 1);
978 return coded_index_desc [kind + idx];
981 static guint32
982 make_coded_token (int kind, guint32 table, guint32 table_idx)
984 guint32 bits = coded_index_desc [kind++];
985 guint32 tables = coded_index_desc [kind++];
986 guint32 i;
987 for (i = 0; i < tables; ++i) {
988 if (coded_index_desc [kind++] == table)
989 return ((table_idx + 1) << bits) | i;
991 g_assert_not_reached ();
992 return -1;
995 static gboolean
996 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
998 guint32 bits = coded_index_desc [token_kind++];
999 guint32 table_count = coded_index_desc [token_kind++];
1000 guint32 table = coded_token & ((1 << bits) - 1);
1001 guint32 token = coded_token >> bits;
1003 if (table >= table_count)
1004 return FALSE;
1006 /*token_kind points to the first table idx*/
1007 table = coded_index_desc [token_kind + table];
1009 if (table == INVALID_TABLE)
1010 return FALSE;
1011 return token <= ctx->image->tables [table].rows;
1014 typedef struct {
1015 guint32 token;
1016 guint32 col_size;
1017 guint32 col_offset;
1018 MonoTableInfo *table;
1019 } RowLocator;
1021 static int
1022 token_locator (const void *a, const void *b)
1024 RowLocator *loc = (RowLocator *)a;
1025 unsigned const char *row = (unsigned const char *)b;
1026 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1028 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1029 return (int)loc->token - (int)token;
1032 static int
1033 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1035 MonoTableInfo *tinfo = &ctx->image->tables [table];
1036 RowLocator locator;
1037 const char *res, *base;
1038 locator.token = coded_token;
1039 locator.col_offset = get_col_offset (ctx, table, column);
1040 locator.col_size = get_col_size (ctx, table, column);
1041 locator.table = tinfo;
1043 base = tinfo->base;
1045 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) );
1046 res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1047 if (!res)
1048 return -1;
1050 return (res - base) / tinfo->row_size;
1053 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1054 static const char*
1055 get_string_ptr (VerifyContext *ctx, guint offset)
1057 return ctx->image->heap_strings.data + offset;
1060 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1061 static int
1062 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1064 if (offset == 0)
1065 return strcmp (str, "");
1067 return strcmp (str, get_string_ptr (ctx, offset));
1070 static gboolean
1071 mono_verifier_is_corlib (MonoImage *image)
1073 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
1074 TRUE : mono_security_core_clr_is_platform_image (image);
1076 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1079 static gboolean
1080 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1082 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1085 static gboolean
1086 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1088 unsigned char b;
1089 const unsigned char *ptr = (const unsigned char *)_ptr;
1091 if (!available)
1092 return FALSE;
1094 b = *ptr;
1095 *value = *size = 0;
1097 if ((b & 0x80) == 0) {
1098 *size = 1;
1099 *value = b;
1100 } else if ((b & 0x40) == 0) {
1101 if (available < 2)
1102 return FALSE;
1103 *size = 2;
1104 *value = ((b & 0x3f) << 8 | ptr [1]);
1105 } else {
1106 if (available < 4)
1107 return FALSE;
1108 *size = 4;
1109 *value = ((b & 0x1f) << 24) |
1110 (ptr [1] << 16) |
1111 (ptr [2] << 8) |
1112 ptr [3];
1115 return TRUE;
1118 static gboolean
1119 decode_signature_header (VerifyContext *ctx, guint32 offset, guint32 *size, const char **first_byte)
1121 MonoStreamHeader blob = ctx->image->heap_blob;
1122 guint32 value, enc_size;
1124 if (offset >= blob.size)
1125 return FALSE;
1127 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1128 return FALSE;
1130 if (CHECK_ADD4_OVERFLOW_UN (offset, enc_size))
1131 return FALSE;
1133 offset += enc_size;
1135 if (ADD_IS_GREATER_OR_OVF (offset, value, blob.size))
1136 return FALSE;
1138 *size = value;
1139 *first_byte = blob.data + offset;
1140 return TRUE;
1143 static gboolean
1144 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1146 const char *ptr = *_ptr;
1147 if (ptr + size > limit)
1148 return FALSE;
1149 switch (size) {
1150 case 1:
1151 *dest = *((guint8*)ptr);
1152 ++ptr;
1153 break;
1154 case 2:
1155 *dest = read16 (ptr);
1156 ptr += 2;
1157 break;
1158 case 4:
1159 *dest = read32 (ptr);
1160 ptr += 4;
1161 break;
1163 *_ptr = ptr;
1164 return TRUE;
1167 static gboolean
1168 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1170 unsigned size = 0;
1171 const char *ptr = *_ptr;
1172 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1173 *_ptr = ptr + size;
1174 return res;
1177 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1178 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1179 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1180 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1182 static gboolean
1183 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1185 static gboolean
1186 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1188 static gboolean
1189 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1191 const char *ptr = *_ptr;
1192 unsigned type = 0;
1193 unsigned token = 0;
1195 while (TRUE) {
1196 if (!safe_read8 (type, ptr, end))
1197 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1199 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1200 --ptr;
1201 break;
1204 if (!safe_read_cint (token, ptr, end))
1205 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1207 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1208 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1211 *_ptr = ptr;
1212 return TRUE;
1215 static gboolean
1216 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1218 const char *ptr = *_ptr;
1219 unsigned val = 0;
1220 unsigned size, num, i;
1222 if (!safe_read8 (val, ptr, end))
1223 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1225 if (val == 0)
1226 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1228 if (!safe_read_cint (size, ptr, end))
1229 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1231 for (i = 0; i < size; ++i) {
1232 if (!safe_read_cint (num, ptr, end))
1233 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1236 if (!safe_read_cint (size, ptr, end))
1237 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1239 for (i = 0; i < size; ++i) {
1240 if (!safe_read_cint (num, ptr, end))
1241 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1244 *_ptr = ptr;
1245 return TRUE;
1248 static gboolean
1249 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1251 const char *ptr = *_ptr;
1252 unsigned type;
1253 unsigned count, token, i;
1255 if (!safe_read8 (type, ptr, end))
1256 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1258 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1259 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1261 if (!safe_read_cint (token, ptr, end))
1262 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1264 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1265 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1267 if (ctx->token) {
1268 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1269 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1270 FAIL (ctx, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx->token));
1273 if (!safe_read_cint (count, ptr, end))
1274 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1276 if (count == 0)
1277 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1279 for (i = 0; i < count; ++i) {
1280 if (!parse_type (ctx, &ptr, end))
1281 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1283 *_ptr = ptr;
1284 return TRUE;
1287 static gboolean
1288 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1290 const char *ptr = *_ptr;
1291 unsigned type;
1292 unsigned token = 0;
1294 if (!safe_read8 (type, ptr, end))
1295 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1297 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1298 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1299 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1300 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1301 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1303 switch (type) {
1304 case MONO_TYPE_PTR:
1305 if (!parse_custom_mods (ctx, &ptr, end))
1306 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1308 if (!safe_read8 (type, ptr, end))
1309 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1311 if (type != MONO_TYPE_VOID) {
1312 --ptr;
1313 if (!parse_type (ctx, &ptr, end))
1314 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1316 break;
1318 case MONO_TYPE_VALUETYPE:
1319 case MONO_TYPE_CLASS:
1320 if (!safe_read_cint (token, ptr, end))
1321 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1323 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1324 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1325 if (ctx->token) {
1326 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1327 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1328 FAIL (ctx, g_strdup_printf ("Type: Recurside type specification (%x). A type signature can't reference itself", ctx->token));
1330 break;
1332 case MONO_TYPE_VAR:
1333 case MONO_TYPE_MVAR:
1334 if (!safe_read_cint (token, ptr, end))
1335 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1336 break;
1338 case MONO_TYPE_ARRAY:
1339 if (!parse_type (ctx, &ptr, end))
1340 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1341 if (!parse_array_shape (ctx, &ptr, end))
1342 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1343 break;
1345 case MONO_TYPE_GENERICINST:
1346 if (!parse_generic_inst (ctx, &ptr, end))
1347 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1348 break;
1350 case MONO_TYPE_FNPTR:
1351 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1352 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1353 break;
1355 case MONO_TYPE_SZARRAY:
1356 if (!parse_custom_mods (ctx, &ptr, end))
1357 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1358 if (!parse_type (ctx, &ptr, end))
1359 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1360 break;
1362 *_ptr = ptr;
1363 return TRUE;
1366 static gboolean
1367 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1369 const char *ptr;
1370 unsigned type = 0;
1372 if (!parse_custom_mods (ctx, _ptr, end))
1373 return FALSE;
1375 ptr = *_ptr;
1376 if (!safe_read8 (type, ptr, end))
1377 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1379 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1380 *_ptr = ptr;
1381 return TRUE;
1384 //it's a byref, update the cursor ptr
1385 if (type == MONO_TYPE_BYREF)
1386 *_ptr = ptr;
1388 return parse_type (ctx, _ptr, end);
1391 static gboolean
1392 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1394 const char *ptr;
1395 unsigned type = 0;
1397 if (!parse_custom_mods (ctx, _ptr, end))
1398 return FALSE;
1400 ptr = *_ptr;
1401 if (!safe_read8 (type, ptr, end))
1402 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1404 if (type == MONO_TYPE_TYPEDBYREF) {
1405 *_ptr = ptr;
1406 return TRUE;
1409 //it's a byref, update the cursor ptr
1410 if (type == MONO_TYPE_BYREF)
1411 *_ptr = ptr;
1413 return parse_type (ctx, _ptr, end);
1416 static gboolean
1417 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1419 unsigned cconv = 0;
1420 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1421 const char *ptr = *_ptr;
1422 gboolean saw_sentinel = FALSE;
1424 if (!safe_read8 (cconv, ptr, end))
1425 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1427 if (cconv & 0x80)
1428 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1430 if (allow_unmanaged) {
1431 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1432 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1433 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1434 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1436 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1437 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1439 if ((cconv & 0x10) && gparam_count == 0)
1440 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1442 if (allow_unmanaged && (cconv & 0x10))
1443 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1445 if (!safe_read_cint (param_count, ptr, end))
1446 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1448 if (!parse_return_type (ctx, &ptr, end))
1449 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1451 for (i = 0; i < param_count; ++i) {
1452 if (allow_sentinel) {
1453 if (!safe_read8 (type, ptr, end))
1454 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1456 if (type == MONO_TYPE_SENTINEL) {
1457 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1458 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1460 if (saw_sentinel)
1461 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1463 saw_sentinel = TRUE;
1464 } else {
1465 --ptr;
1469 if (!parse_param (ctx, &ptr, end))
1470 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1473 *_ptr = ptr;
1474 return TRUE;
1477 static gboolean
1478 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1480 unsigned sig = 0;
1481 unsigned param_count = 0, i;
1482 const char *ptr = *_ptr;
1484 if (!safe_read8 (sig, ptr, end))
1485 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1487 if (sig != 0x08 && sig != 0x28)
1488 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1490 if (!safe_read_cint (param_count, ptr, end))
1491 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1493 if (!parse_custom_mods (ctx, &ptr, end))
1494 return FALSE;
1496 if (!parse_type (ctx, &ptr, end))
1497 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1499 for (i = 0; i < param_count; ++i) {
1500 if (!parse_type (ctx, &ptr, end))
1501 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1504 *_ptr = ptr;
1505 return TRUE;
1508 static gboolean
1509 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1511 const char *ptr = *_ptr;
1512 unsigned signature = 0;
1514 if (!safe_read8 (signature, ptr, end))
1515 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1517 if (signature != 0x06)
1518 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1520 if (!parse_custom_mods (ctx, &ptr, end))
1521 return FALSE;
1523 if (safe_read8 (signature, ptr, end)) {
1524 if (signature != MONO_TYPE_BYREF)
1525 --ptr;
1527 *_ptr = ptr;
1529 return parse_type (ctx, _ptr, end);
1532 static gboolean
1533 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1535 unsigned sig = 0;
1536 unsigned locals_count = 0, i;
1537 const char *ptr = *_ptr;
1539 if (!safe_read8 (sig, ptr, end))
1540 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1542 if (sig != 0x07)
1543 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1545 if (!safe_read_cint (locals_count, ptr, end))
1546 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1548 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1549 if (locals_count == 0)
1550 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1553 for (i = 0; i < locals_count; ++i) {
1554 if (!safe_read8 (sig, ptr, end))
1555 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1557 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1558 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1559 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1560 if (!safe_read8 (sig, ptr, end))
1561 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1564 if (sig == MONO_TYPE_BYREF) {
1565 if (!safe_read8 (sig, ptr, end))
1566 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1567 if (sig == MONO_TYPE_TYPEDBYREF)
1568 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1571 if (sig == MONO_TYPE_TYPEDBYREF)
1572 continue;
1574 --ptr;
1576 if (!parse_type (ctx, &ptr, end))
1577 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1580 *_ptr = ptr;
1581 return TRUE;
1584 static gboolean
1585 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1587 guint32 size = 0;
1588 unsigned signature = 0;
1589 const char *ptr = NULL, *end;
1591 if (!decode_signature_header (ctx, offset, &size, &ptr))
1592 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1593 end = ptr + size;
1595 if (!safe_read8 (signature, ptr, end))
1596 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1598 if (signature != 6)
1599 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1600 --ptr;
1602 return parse_field (ctx, &ptr, end);
1605 static gboolean
1606 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1608 guint32 size = 0;
1609 const char *ptr = NULL, *end;
1611 if (!decode_signature_header (ctx, offset, &size, &ptr))
1612 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1613 end = ptr + size;
1615 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1618 static gboolean
1619 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1621 guint32 size = 0;
1622 unsigned signature = 0;
1623 const char *ptr = NULL, *end;
1625 if (!decode_signature_header (ctx, offset, &size, &ptr))
1626 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1627 end = ptr + size;
1629 if (!safe_read8 (signature, ptr, end))
1630 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1631 --ptr;
1633 if (signature == 0x06)
1634 return parse_field (ctx, &ptr, end);
1636 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1639 static gboolean
1640 is_valid_cattr_blob (VerifyContext *ctx, guint32 offset)
1642 guint32 size = 0;
1643 unsigned prolog = 0;
1644 const char *ptr = NULL, *end;
1646 if (!offset)
1647 return TRUE;
1649 if (!decode_signature_header (ctx, offset, &size, &ptr))
1650 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1651 end = ptr + size;
1653 if (!safe_read16 (prolog, ptr, end))
1654 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1656 if (prolog != 1)
1657 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1659 return TRUE;
1662 static gboolean
1663 is_valid_cattr_type (MonoType *type)
1665 MonoClass *klass;
1667 if (type->type == MONO_TYPE_OBJECT || (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_STRING))
1668 return TRUE;
1670 if (type->type == MONO_TYPE_VALUETYPE) {
1671 klass = mono_class_from_mono_type (type);
1672 return klass && klass->enumtype;
1675 if (type->type == MONO_TYPE_CLASS)
1676 return mono_class_from_mono_type (type) == mono_defaults.systemtype_class;
1678 return FALSE;
1681 static gboolean
1682 is_valid_ser_string_full (VerifyContext *ctx, const char **str_start, guint32 *str_len, const char **_ptr, const char *end)
1684 guint32 size = 0;
1685 const char *ptr = *_ptr;
1687 *str_start = NULL;
1688 *str_len = 0;
1690 if (ptr >= end)
1691 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1693 /*NULL string*/
1694 if (*ptr == (char)0xFF) {
1695 *_ptr = ptr + 1;
1696 return TRUE;
1699 if (!safe_read_cint (size, ptr, end))
1700 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1702 if (ADDP_IS_GREATER_OR_OVF (ptr, size, end))
1703 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string"));
1705 *str_start = ptr;
1706 *str_len = size;
1708 *_ptr = ptr + size;
1709 return TRUE;
1712 static gboolean
1713 is_valid_ser_string (VerifyContext *ctx, const char **_ptr, const char *end)
1715 const char *dummy_str;
1716 guint32 dummy_int;
1717 return is_valid_ser_string_full (ctx, &dummy_str, &dummy_int, _ptr, end);
1720 static MonoClass*
1721 get_enum_by_encoded_name (VerifyContext *ctx, const char **_ptr, const char *end)
1723 MonoType *type;
1724 MonoClass *klass;
1725 const char *str_start = NULL;
1726 const char *ptr = *_ptr;
1727 char *enum_name;
1728 guint32 str_len = 0;
1730 if (!is_valid_ser_string_full (ctx, &str_start, &str_len, &ptr, end))
1731 return NULL;
1733 /*NULL or empty string*/
1734 if (str_start == NULL || str_len == 0) {
1735 ADD_ERROR_NO_RETURN (ctx, g_strdup ("CustomAttribute: Null or empty enum name"));
1736 return NULL;
1739 enum_name = g_memdup (str_start, str_len + 1);
1740 enum_name [str_len] = 0;
1741 type = mono_reflection_type_from_name (enum_name, ctx->image);
1742 if (!type) {
1743 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid enum class %s", enum_name));
1744 g_free (enum_name);
1745 return NULL;
1747 g_free (enum_name);
1749 klass = mono_class_from_mono_type (type);
1750 if (!klass || !klass->enumtype) {
1751 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute:Class %s::%s is not an enum", klass->name_space, klass->name));
1752 return NULL;
1755 *_ptr = ptr;
1756 return klass;
1759 static gboolean
1760 is_valid_fixed_param (VerifyContext *ctx, MonoType *mono_type, const char **_ptr, const char *end)
1762 MonoClass *klass;
1763 const char *ptr = *_ptr;
1764 int elem_size = 0;
1765 guint32 element_count, i;
1766 int type;
1768 klass = mono_type->data.klass;
1769 type = mono_type->type;
1771 handle_enum:
1772 switch (type) {
1773 case MONO_TYPE_BOOLEAN:
1774 case MONO_TYPE_I1:
1775 case MONO_TYPE_U1:
1776 elem_size = 1;
1777 break;
1778 case MONO_TYPE_I2:
1779 case MONO_TYPE_U2:
1780 case MONO_TYPE_CHAR:
1781 elem_size = 2;
1782 break;
1783 case MONO_TYPE_I4:
1784 case MONO_TYPE_U4:
1785 case MONO_TYPE_R4:
1786 elem_size = 4;
1787 break;
1788 case MONO_TYPE_I8:
1789 case MONO_TYPE_U8:
1790 case MONO_TYPE_R8:
1791 elem_size = 8;
1792 break;
1794 case MONO_TYPE_STRING:
1795 *_ptr = ptr;
1796 return is_valid_ser_string (ctx, _ptr, end);
1798 case MONO_TYPE_OBJECT: {
1799 unsigned sub_type = 0;
1800 if (!safe_read8 (sub_type, ptr, end))
1801 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array type"));
1803 if (sub_type >= MONO_TYPE_BOOLEAN && sub_type <= MONO_TYPE_STRING) {
1804 type = sub_type;
1805 goto handle_enum;
1807 if (sub_type == MONO_TYPE_ENUM) {
1808 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1809 if (!klass)
1810 return FALSE;
1812 klass = klass->element_class;
1813 type = klass->byval_arg.type;
1814 goto handle_enum;
1816 if (sub_type == 0x50) { /*Type*/
1817 *_ptr = ptr;
1818 return is_valid_ser_string (ctx, _ptr, end);
1820 if (sub_type == MONO_TYPE_SZARRAY) {
1821 MonoType simple_type = {{0}};
1822 unsigned etype = 0;
1823 if (!safe_read8 (etype, ptr, end))
1824 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1826 if (etype == MONO_TYPE_ENUM) {
1827 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1828 if (!klass)
1829 return FALSE;
1830 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1831 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
1832 klass = mono_class_from_mono_type (&simple_type);
1833 } else
1834 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1836 type = MONO_TYPE_SZARRAY;
1837 goto handle_enum;
1839 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type));
1843 case MONO_TYPE_CLASS:
1844 if (klass != mono_defaults.systemtype_class)
1845 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1846 *_ptr = ptr;
1847 return is_valid_ser_string (ctx, _ptr, end);
1849 case MONO_TYPE_VALUETYPE:
1850 if (!klass || !klass->enumtype)
1851 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass->name_space, klass->name));
1853 klass = klass->element_class;
1854 type = klass->byval_arg.type;
1855 goto handle_enum;
1857 case MONO_TYPE_SZARRAY:
1858 mono_type = &klass->byval_arg;
1859 if (!is_valid_cattr_type (mono_type))
1860 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass->name_space, klass->name));
1861 if (!safe_read32 (element_count, ptr, end))
1862 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1863 if (element_count == 0xFFFFFFFFu) {
1864 *_ptr = ptr;
1865 return TRUE;
1867 for (i = 0; i < element_count; ++i) {
1868 if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
1869 return FALSE;
1871 *_ptr = ptr;
1872 return TRUE;
1873 default:
1874 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
1877 if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
1878 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
1879 *_ptr = ptr + elem_size;
1880 return TRUE;
1883 static gboolean
1884 is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
1886 MonoError error;
1887 unsigned prolog = 0;
1888 const char *end;
1889 MonoMethodSignature *sig;
1890 int args, i;
1891 unsigned num_named;
1893 if (!ctor)
1894 FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
1896 sig = mono_method_signature_checked (ctor, &error);
1897 if (!mono_error_ok (&error)) {
1898 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error)));
1899 mono_error_cleanup (&error);
1900 return FALSE;
1903 if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
1904 FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1906 end = ptr + size;
1908 if (!safe_read16 (prolog, ptr, end))
1909 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1911 if (prolog != 1)
1912 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1914 args = sig->param_count;
1915 for (i = 0; i < args; ++i) {
1916 MonoType *arg_type = sig->params [i];
1917 if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
1918 return FALSE;
1921 if (!safe_read16 (num_named, ptr, end))
1922 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
1924 for (i = 0; i < num_named; ++i) {
1925 MonoType *type, simple_type = {{0}};
1926 unsigned kind;
1928 if (!safe_read8 (kind, ptr, end))
1929 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
1930 if (kind != 0x53 && kind != 0x54)
1931 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
1932 if (!safe_read8 (kind, ptr, end))
1933 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
1935 if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
1936 simple_type.type = kind;
1937 type = &simple_type;
1938 } else if (kind == MONO_TYPE_ENUM) {
1939 MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
1940 if (!klass)
1941 return FALSE;
1942 type = &klass->byval_arg;
1943 } else if (kind == 0x50) {
1944 type = &mono_defaults.systemtype_class->byval_arg;
1945 } else if (kind == 0x51) {
1946 type = &mono_defaults.object_class->byval_arg;
1947 } else if (kind == MONO_TYPE_SZARRAY) {
1948 MonoClass *klass;
1949 unsigned etype = 0;
1950 if (!safe_read8 (etype, ptr, end))
1951 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1953 if (etype == MONO_TYPE_ENUM) {
1954 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1955 if (!klass)
1956 return FALSE;
1957 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1958 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
1959 klass = mono_class_from_mono_type (&simple_type);
1960 } else
1961 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1963 type = &mono_array_class_get (klass, 1)->byval_arg;
1964 } else {
1965 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
1968 if (!is_valid_ser_string (ctx, &ptr, end))
1969 return FALSE;
1971 if (!is_valid_fixed_param (ctx, type, &ptr, end))
1972 return FALSE;
1976 return TRUE;
1979 static gboolean
1980 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1982 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1983 //TODO do proper verification
1984 return blob.size >= 1 && blob.size - 1 >= offset;
1987 static gboolean
1988 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1990 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1991 //TODO do proper verification
1992 return blob.size >= 1 && blob.size - 1 >= offset;
1995 static gboolean
1996 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1998 guint32 size = 0;
1999 unsigned signature = 0;
2000 const char *ptr = NULL, *end;
2002 if (!decode_signature_header (ctx, offset, &size, &ptr))
2003 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
2004 end = ptr + size;
2006 if (!safe_read8 (signature, ptr, end))
2007 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2009 --ptr;
2010 if (signature == 0x07)
2011 return parse_locals_signature (ctx, &ptr, end);
2013 /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
2014 if (signature == 0x06)
2015 return parse_field (ctx, &ptr, end);
2017 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
2020 static gboolean
2021 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
2023 guint32 size = 0;
2024 const char *ptr = NULL, *end;
2026 if (!decode_signature_header (ctx, offset, &size, &ptr))
2027 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
2028 end = ptr + size;
2030 return parse_property_signature (ctx, &ptr, end);
2033 static gboolean
2034 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
2036 guint32 size = 0;
2037 const char *ptr = NULL, *end;
2038 unsigned type = 0;
2040 if (!decode_signature_header (ctx, offset, &size, &ptr))
2041 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
2042 end = ptr + size;
2044 if (!parse_custom_mods (ctx, &ptr, end))
2045 return FALSE;
2047 if (!safe_read8 (type, ptr, end))
2048 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
2050 if (type == MONO_TYPE_BYREF) {
2051 if (!safe_read8 (type, ptr, end))
2052 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
2053 if (type == MONO_TYPE_TYPEDBYREF)
2054 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
2057 if (type == MONO_TYPE_TYPEDBYREF)
2058 return TRUE;
2060 --ptr;
2061 return parse_type (ctx, &ptr, end);
2064 static gboolean
2065 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
2067 guint32 size = 0;
2068 const char *ptr = NULL, *end;
2069 unsigned type = 0;
2070 unsigned count = 0, i;
2072 if (!decode_signature_header (ctx, offset, &size, &ptr))
2073 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
2074 end = ptr + size;
2076 if (!safe_read8 (type, ptr, end))
2077 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
2079 if (type != 0x0A)
2080 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
2082 if (!safe_read_cint (count, ptr, end))
2083 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
2085 if (!count)
2086 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
2088 for (i = 0; i < count; ++i) {
2089 if (!parse_type (ctx, &ptr, end))
2090 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
2092 return TRUE;
2095 static gboolean
2096 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
2098 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2099 guint32 entry_size, bytes;
2101 if (blob.size < offset)
2102 return FALSE;
2104 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2105 return FALSE;
2107 if (entry_size < minsize)
2108 return FALSE;
2110 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
2111 return FALSE;
2112 entry_size += bytes;
2114 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
2117 static gboolean
2118 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
2120 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2121 guint32 size, entry_size, bytes;
2123 if (blob.size < offset)
2124 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
2126 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2127 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
2129 if (type == MONO_TYPE_STRING) {
2130 //String is encoded as: compressed_int:len len *bytes
2131 offset += bytes;
2133 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
2134 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
2136 return TRUE;
2139 switch (type) {
2140 case MONO_TYPE_BOOLEAN:
2141 case MONO_TYPE_I1:
2142 case MONO_TYPE_U1:
2143 size = 1;
2144 break;
2145 case MONO_TYPE_CHAR:
2146 case MONO_TYPE_I2:
2147 case MONO_TYPE_U2:
2148 size = 2;
2149 break;
2150 case MONO_TYPE_I4:
2151 case MONO_TYPE_U4:
2152 case MONO_TYPE_R4:
2153 case MONO_TYPE_CLASS:
2154 size = 4;
2155 break;
2157 case MONO_TYPE_I8:
2158 case MONO_TYPE_U8:
2159 case MONO_TYPE_R8:
2160 size = 8;
2161 break;
2162 default:
2163 g_assert_not_reached ();
2166 if (size != entry_size)
2167 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
2169 offset += bytes;
2171 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
2172 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
2174 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
2175 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
2176 return TRUE;
2179 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
2180 //only 0x01, 0x40 and 0x80 are allowed
2181 #define SECTION_HEADER_INVALID_FLAGS 0x3E
2183 static gboolean
2184 is_valid_method_header (VerifyContext *ctx, guint32 rva)
2186 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
2187 unsigned header = 0;
2188 unsigned fat_header = 0, size = 0, max_stack;
2189 const char *ptr = NULL, *end;
2191 if (offset == INVALID_ADDRESS)
2192 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
2194 ptr = ctx->data + offset;
2195 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
2197 if (!safe_read8 (header, ptr, end))
2198 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
2200 switch (header & 0x3) {
2201 case 0:
2202 case 1:
2203 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
2204 case 2:
2205 header >>= 2;
2206 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
2207 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
2208 return TRUE;
2210 //FAT HEADER
2211 --ptr;
2212 if (!safe_read16 (fat_header, ptr, end))
2213 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
2215 size = (fat_header >> 12) & 0xF;
2216 if (size != 3)
2217 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
2219 if (!safe_read16 (max_stack, ptr, end))
2220 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
2222 if (!safe_read32 (code_size, ptr, end))
2223 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
2225 if (!safe_read32 (local_vars_tok, ptr, end))
2226 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
2228 if (local_vars_tok) {
2229 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
2230 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
2231 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
2232 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
2235 if (fat_header & FAT_HEADER_INVALID_FLAGS)
2236 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
2238 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
2239 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
2241 if (!(fat_header & 0x08))
2242 return TRUE;
2244 ptr += code_size;
2246 do {
2247 unsigned section_header = 0, section_size = 0;
2248 gboolean is_fat;
2250 ptr = dword_align (ptr);
2251 if (!safe_read32 (section_header, ptr, end))
2252 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
2254 if (section_header & SECTION_HEADER_INVALID_FLAGS)
2255 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
2257 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
2258 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
2260 if (section_size < 4)
2261 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
2263 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
2264 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
2266 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
2267 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
2269 LAMEIMPL: MS emits section_size without accounting for header size.
2270 Mono does as the spec says. section_size is header + section
2271 MS's peverify happily accepts both.
2273 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
2274 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)));
2276 /* only verify the class token is verified as the rest is done by the IL verifier*/
2277 for (i = 0; i < clauses; ++i) {
2278 unsigned flags = *(unsigned char*)ptr;
2279 unsigned class_token = 0;
2280 ptr += (is_fat ? 20 : 8);
2281 if (!safe_read32 (class_token, ptr, end))
2282 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
2283 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
2284 guint table = mono_metadata_token_table (class_token);
2285 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
2286 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
2287 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
2288 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
2293 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
2294 break;
2295 } while (1);
2296 return TRUE;
2299 static void
2300 verify_module_table (VerifyContext *ctx)
2302 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
2303 guint32 data [MONO_MODULE_SIZE];
2305 if (table->rows != 1)
2306 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
2308 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
2310 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
2311 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
2313 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
2314 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
2316 if (data [MONO_MODULE_ENC] != 0)
2317 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
2319 if (data [MONO_MODULE_ENCBASE] != 0)
2320 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
2323 static void
2324 verify_typeref_table (VerifyContext *ctx)
2326 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2327 guint32 data [MONO_TYPEREF_SIZE];
2328 int i;
2330 for (i = 0; i < table->rows; ++i) {
2331 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
2332 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
2333 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
2335 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
2336 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
2338 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
2339 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
2341 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2342 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
2346 /*bits 9,11,14,15,19,21,24-31 */
2347 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2348 static void
2349 verify_typedef_table (VerifyContext *ctx)
2351 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2352 guint32 data [MONO_TYPEDEF_SIZE];
2353 guint32 fieldlist = 1, methodlist = 1, visibility;
2354 int i;
2356 if (table->rows == 0)
2357 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2359 for (i = 0; i < table->rows; ++i) {
2360 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2361 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2362 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2364 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2365 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2367 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2368 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2370 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
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] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2374 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2376 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2377 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2379 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2380 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2382 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2383 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2385 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2386 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2387 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2388 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2390 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2391 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2393 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2394 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2396 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2397 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));
2399 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2400 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2402 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2403 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2405 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2406 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));
2408 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2409 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2413 static void
2414 verify_typedef_table_full (VerifyContext *ctx)
2416 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2417 guint32 data [MONO_TYPEDEF_SIZE];
2418 int i;
2420 if (table->rows == 0)
2421 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2423 for (i = 0; i < table->rows; ++i) {
2424 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2426 if (i == 0) {
2427 /*XXX it's ok if <module> extends object, or anything at all, actually. */
2428 /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
2429 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2431 continue;
2434 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2435 if (data [MONO_TYPEDEF_EXTENDS])
2436 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2437 } else {
2438 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2439 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2441 if (is_sys_obj) {
2442 if (has_parent)
2443 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2444 } else {
2445 if (!has_parent) {
2446 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2453 /*bits 3,11,14 */
2454 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2455 static void
2456 verify_field_table (VerifyContext *ctx)
2458 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2459 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2460 int i;
2462 module_field_list = (guint32)-1;
2463 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2464 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2465 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2468 for (i = 0; i < table->rows; ++i) {
2469 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2470 flags = data [MONO_FIELD_FLAGS];
2472 if (flags & INVALID_FIELD_FLAG_BITS)
2473 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2475 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2476 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2478 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2479 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2481 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2482 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2484 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2485 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2487 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2488 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2489 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2491 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2492 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2493 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2495 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2496 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2497 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2499 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2500 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2501 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2503 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2504 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2506 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2507 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2509 //TODO verify contant flag
2511 if (i + 1 < module_field_list) {
2512 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2513 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2514 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2515 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2516 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2521 static void
2522 verify_field_table_full (VerifyContext *ctx)
2524 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2525 guint32 data [MONO_FIELD_SIZE];
2526 int i;
2528 for (i = 0; i < table->rows; ++i) {
2529 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2531 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2532 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2536 /*bits 8,9,10,11,13,14,15*/
2537 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2538 static void
2539 verify_method_table (VerifyContext *ctx)
2541 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2542 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2543 guint32 paramlist = 1;
2544 gboolean is_ctor, is_cctor;
2545 const char *name;
2546 int i;
2548 module_method_list = (guint32)-1;
2549 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2550 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2551 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2554 for (i = 0; i < table->rows; ++i) {
2555 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2556 rva = data [MONO_METHOD_RVA];
2557 implflags = data [MONO_METHOD_IMPLFLAGS];
2558 flags = data [MONO_METHOD_FLAGS];
2559 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2560 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2563 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2564 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2566 if (access == 0x7)
2567 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2569 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2570 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2572 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2573 is_ctor = !strcmp (".ctor", name);
2574 is_cctor = !strcmp (".cctor", name);
2576 if ((is_ctor || is_cctor) &&
2577 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2578 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2580 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2581 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2583 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2584 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2585 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2586 if (flags & METHOD_ATTRIBUTE_FINAL)
2587 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2588 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2589 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2592 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2593 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2595 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2596 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2598 //XXX no checks against cas stuff 10,11,12,13)
2600 //TODO check iface with .ctor (15,16)
2602 if (i + 1 < module_method_list) {
2603 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2604 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2605 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2606 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2607 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2608 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2611 //TODO check valuetype for synchronized
2613 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2614 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2616 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2617 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2618 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2619 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2620 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2623 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2624 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2625 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2627 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2628 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2630 //TODO check signature contents
2632 if (rva) {
2633 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2634 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2635 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2636 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2637 } else {
2638 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2639 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2642 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2643 if (rva)
2644 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2645 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2646 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2648 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2649 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2651 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2652 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2654 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2655 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2657 if (data [MONO_METHOD_PARAMLIST] == 0)
2658 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2660 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2661 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));
2663 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2664 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2666 paramlist = data [MONO_METHOD_PARAMLIST];
2671 static void
2672 verify_method_table_full (VerifyContext *ctx)
2674 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2675 guint32 data [MONO_METHOD_SIZE], rva;
2676 int i;
2678 for (i = 0; i < table->rows; ++i) {
2679 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2680 rva = data [MONO_METHOD_RVA];
2682 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2683 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2685 if (rva && !is_valid_method_header (ctx, rva))
2686 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2690 static guint32
2691 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2693 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2694 guint32 row = *current_method;
2695 guint32 paramlist, tmp;
2698 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2699 while (row < table->rows) {
2700 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2701 if (tmp > paramlist) {
2702 *current_method = row;
2703 return tmp - paramlist;
2705 ++row;
2708 /*no more methods, all params apply to the last one*/
2709 *current_method = table->rows;
2710 return (guint32)-1;
2714 #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))
2715 static void
2716 verify_param_table (VerifyContext *ctx)
2718 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2719 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2720 gboolean first_param = TRUE;
2721 int i;
2723 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2724 if (table->rows > 0)
2725 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2726 return;
2729 remaining_params = get_next_param_count (ctx, &current_method);
2731 for (i = 0; i < table->rows; ++i) {
2732 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2733 flags = data [MONO_PARAM_FLAGS];
2735 if (flags & INVALID_PARAM_FLAGS_BITS)
2736 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2738 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2739 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2740 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2741 } else {
2742 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2743 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2746 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)
2747 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2749 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2750 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2752 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2753 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2755 first_param = FALSE;
2756 sequence = data [MONO_PARAM_SEQUENCE];
2757 if (--remaining_params == 0) {
2758 remaining_params = get_next_param_count (ctx, &current_method);
2759 first_param = TRUE;
2764 static void
2765 verify_interfaceimpl_table (VerifyContext *ctx)
2767 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2768 guint32 data [MONO_INTERFACEIMPL_SIZE];
2769 int i;
2771 for (i = 0; i < table->rows; ++i) {
2772 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2773 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2774 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2776 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2777 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2779 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2780 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2784 static void
2785 verify_memberref_table (VerifyContext *ctx)
2787 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2788 guint32 data [MONO_MEMBERREF_SIZE];
2789 int i;
2791 for (i = 0; i < table->rows; ++i) {
2792 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2794 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2795 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2797 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2798 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2800 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2801 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2803 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2804 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2809 static void
2810 verify_memberref_table_full (VerifyContext *ctx)
2812 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2813 guint32 data [MONO_MEMBERREF_SIZE];
2814 int i;
2816 for (i = 0; i < table->rows; ++i) {
2817 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2819 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2820 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2824 static void
2825 verify_constant_table (VerifyContext *ctx)
2827 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2828 guint32 data [MONO_CONSTANT_SIZE], type;
2829 int i;
2831 for (i = 0; i < table->rows; ++i) {
2832 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2833 type = data [MONO_CONSTANT_TYPE];
2835 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2836 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2838 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2839 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2841 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2842 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2844 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2845 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2849 static void
2850 verify_cattr_table (VerifyContext *ctx)
2852 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2853 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2854 int i;
2856 for (i = 0; i < table->rows; ++i) {
2857 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2859 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2860 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2862 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2863 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2865 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2866 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2870 static void
2871 verify_cattr_table_full (VerifyContext *ctx)
2873 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2874 MonoMethod *ctor;
2875 const char *ptr;
2876 guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2877 int i;
2879 for (i = 0; i < table->rows; ++i) {
2880 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2882 if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2883 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2885 mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2886 switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2887 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2888 mtoken |= MONO_TOKEN_METHOD_DEF;
2889 break;
2890 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2891 mtoken |= MONO_TOKEN_MEMBER_REF;
2892 break;
2893 default:
2894 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2897 ctor = mono_get_method (ctx->image, mtoken, NULL);
2899 /*This can't fail since this is checked in is_valid_cattr_blob*/
2900 g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
2902 if (!is_valid_cattr_content (ctx, ctor, ptr, size))
2903 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2907 static void
2908 verify_field_marshal_table (VerifyContext *ctx)
2910 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2911 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2912 int i;
2914 for (i = 0; i < table->rows; ++i) {
2915 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2917 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2918 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2920 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2921 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2923 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2924 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2926 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2927 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2931 static void
2932 verify_field_marshal_table_full (VerifyContext *ctx)
2934 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2935 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2936 int i;
2938 for (i = 0; i < table->rows; ++i) {
2939 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2941 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2942 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2946 static void
2947 verify_decl_security_table (VerifyContext *ctx)
2949 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2950 guint32 data [MONO_DECL_SECURITY_SIZE];
2951 int i;
2953 for (i = 0; i < table->rows; ++i) {
2954 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2956 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2957 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2959 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2960 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2962 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2963 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2967 static void
2968 verify_decl_security_table_full (VerifyContext *ctx)
2970 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2971 guint32 data [MONO_DECL_SECURITY_SIZE];
2972 int i;
2974 for (i = 0; i < table->rows; ++i) {
2975 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2977 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2978 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2982 static void
2983 verify_class_layout_table (VerifyContext *ctx)
2985 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2986 guint32 data [MONO_CLASS_LAYOUT_SIZE];
2987 int i;
2989 for (i = 0; i < table->rows; ++i) {
2990 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2992 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2993 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2995 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2996 case 0:
2997 case 1:
2998 case 2:
2999 case 4:
3000 case 8:
3001 case 16:
3002 case 32:
3003 case 64:
3004 case 128:
3005 break;
3006 default:
3007 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3012 static void
3013 verify_field_layout_table (VerifyContext *ctx)
3015 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3016 guint32 data [MONO_FIELD_LAYOUT_SIZE];
3017 int i;
3019 for (i = 0; i < table->rows; ++i) {
3020 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
3022 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3023 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
3027 static void
3028 verify_standalonesig_table (VerifyContext *ctx)
3030 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3031 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3032 int i;
3034 for (i = 0; i < table->rows; ++i) {
3035 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3037 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
3038 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3042 static void
3043 verify_standalonesig_table_full (VerifyContext *ctx)
3045 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3046 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3047 int i;
3049 for (i = 0; i < table->rows; ++i) {
3050 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3052 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
3053 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3057 static void
3058 verify_eventmap_table (VerifyContext *ctx)
3060 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3061 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3062 int i;
3064 for (i = 0; i < table->rows; ++i) {
3065 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
3067 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3068 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
3070 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
3071 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
3073 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
3077 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3078 static void
3079 verify_event_table (VerifyContext *ctx)
3081 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3082 guint32 data [MONO_EVENT_SIZE];
3083 int i;
3085 for (i = 0; i < table->rows; ++i) {
3086 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3088 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
3089 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
3091 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
3092 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
3094 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
3095 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
3099 static void
3100 verify_event_table_full (VerifyContext *ctx)
3102 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3103 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
3104 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
3105 gboolean found_add, found_remove;
3106 int i, idx;
3108 for (i = 0; i < table->rows; ++i) {
3109 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3111 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
3112 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
3113 if (idx == -1)
3114 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
3116 //first we move to the first row for this event
3117 while (idx > 0) {
3118 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3119 break;
3120 --idx;
3122 //now move forward looking for AddOn and RemoveOn rows
3123 found_add = found_remove = FALSE;
3124 while (idx < sema_table->rows) {
3125 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
3126 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
3127 break;
3128 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3129 found_add = TRUE;
3130 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3131 found_remove = TRUE;
3132 if (found_add && found_remove)
3133 break;
3134 ++idx;
3137 if (!found_add)
3138 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3139 if (!found_remove)
3140 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3144 static void
3145 verify_propertymap_table (VerifyContext *ctx)
3147 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3148 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3149 int i;
3151 for (i = 0; i < table->rows; ++i) {
3152 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
3154 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3155 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
3157 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
3158 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
3160 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
3164 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3165 static void
3166 verify_property_table (VerifyContext *ctx)
3168 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3169 guint32 data [MONO_PROPERTY_SIZE];
3170 int i;
3172 for (i = 0; i < table->rows; ++i) {
3173 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
3175 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
3176 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
3178 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
3179 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
3181 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
3182 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
3184 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
3185 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
3186 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
3191 static void
3192 verify_methodimpl_table (VerifyContext *ctx)
3194 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3195 guint32 data [MONO_METHODIMPL_SIZE];
3196 int i;
3198 for (i = 0; i < table->rows; ++i) {
3199 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3201 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3202 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3204 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3205 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3207 if (!is_valid_coded_index (ctx, 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 (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3211 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3213 if (!is_valid_coded_index (ctx, 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]));
3218 static void
3219 verify_moduleref_table (VerifyContext *ctx)
3221 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3222 guint32 data [MONO_MODULEREF_SIZE];
3223 int i;
3225 for (i = 0; i < table->rows; ++i) {
3226 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
3228 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
3229 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3233 static void
3234 verify_typespec_table (VerifyContext *ctx)
3236 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3237 guint32 data [MONO_TYPESPEC_SIZE];
3238 int i;
3240 for (i = 0; i < table->rows; ++i) {
3241 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3243 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
3244 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3248 static void
3249 verify_typespec_table_full (VerifyContext *ctx)
3251 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3252 guint32 data [MONO_TYPESPEC_SIZE];
3253 int i;
3255 for (i = 0; i < table->rows; ++i) {
3256 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3257 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
3258 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
3259 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3261 ctx->token = 0;
3264 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
3265 static void
3266 verify_implmap_table (VerifyContext *ctx)
3268 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3269 guint32 data [MONO_IMPLMAP_SIZE], cconv;
3270 int i;
3272 for (i = 0; i < table->rows; ++i) {
3273 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
3275 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
3276 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
3278 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
3279 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
3280 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
3282 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3283 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
3285 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
3286 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
3288 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3289 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
3291 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
3292 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
3294 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
3295 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
3299 static void
3300 verify_fieldrva_table (VerifyContext *ctx)
3302 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3303 guint32 data [MONO_FIELD_RVA_SIZE];
3304 int i;
3306 for (i = 0; i < table->rows; ++i) {
3307 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
3309 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
3310 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
3312 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3313 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
3317 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
3318 static void
3319 verify_assembly_table (VerifyContext *ctx)
3321 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3322 guint32 data [MONO_ASSEMBLY_SIZE], hash;
3323 int i;
3325 if (table->rows > 1)
3326 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
3328 for (i = 0; i < table->rows; ++i) {
3329 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
3331 hash = data [MONO_ASSEMBLY_HASH_ALG];
3332 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
3333 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
3335 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
3336 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3338 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
3339 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3341 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3342 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3344 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3345 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3349 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
3350 static void
3351 verify_assemblyref_table (VerifyContext *ctx)
3353 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3354 guint32 data [MONO_ASSEMBLYREF_SIZE];
3355 int i;
3357 for (i = 0; i < table->rows; ++i) {
3358 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3360 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3361 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3363 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3364 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3366 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3367 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3369 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3370 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3372 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3373 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3377 #define INVALID_FILE_FLAGS_BITS ~(1)
3378 static void
3379 verify_file_table (VerifyContext *ctx)
3381 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3382 guint32 data [MONO_FILE_SIZE];
3383 int i;
3385 for (i = 0; i < table->rows; ++i) {
3386 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3388 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3389 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3391 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3392 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3394 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3395 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3399 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3400 static void
3401 verify_exportedtype_table (VerifyContext *ctx)
3403 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3404 guint32 data [MONO_EXP_TYPE_SIZE];
3405 int i;
3407 for (i = 0; i < table->rows; ++i) {
3408 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3410 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3411 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3413 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3414 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3416 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3417 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3419 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3420 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3422 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3423 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3425 /*nested type can't have a namespace*/
3426 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3427 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3431 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3432 static void
3433 verify_manifest_resource_table (VerifyContext *ctx)
3435 MonoCLIImageInfo *iinfo = ctx->image->image_info;
3436 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3437 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3438 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3439 int i;
3441 resources_size = ch->ch_resources.size;
3443 for (i = 0; i < table->rows; ++i) {
3444 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3446 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3447 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3449 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3450 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3452 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3453 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3455 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3456 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3458 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3459 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3461 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3462 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])));
3464 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3465 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3467 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3468 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3472 static void
3473 verify_nested_class_table (VerifyContext *ctx)
3475 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3476 guint32 data [MONO_NESTED_CLASS_SIZE];
3477 int i;
3479 for (i = 0; i < table->rows; ++i) {
3480 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3482 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3483 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3484 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3485 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3486 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3487 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3491 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3492 static void
3493 verify_generic_param_table (VerifyContext *ctx)
3495 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3496 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3497 int i, param_number = 0;
3499 for (i = 0; i < table->rows; ++i) {
3500 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3502 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3503 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3505 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3506 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3508 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3509 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3511 token = data [MONO_GENERICPARAM_OWNER];
3513 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3514 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3516 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3517 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3519 if (token != last_token) {
3520 param_number = 0;
3521 last_token = token;
3524 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3525 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));
3527 ++param_number;
3531 static void
3532 verify_method_spec_table (VerifyContext *ctx)
3534 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3535 guint32 data [MONO_METHODSPEC_SIZE];
3536 int i;
3538 for (i = 0; i < table->rows; ++i) {
3539 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3541 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3542 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3544 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3545 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3547 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3548 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3552 static void
3553 verify_method_spec_table_full (VerifyContext *ctx)
3555 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3556 guint32 data [MONO_METHODSPEC_SIZE];
3557 int i;
3559 for (i = 0; i < table->rows; ++i) {
3560 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3562 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3563 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3567 static void
3568 verify_generic_param_constraint_table (VerifyContext *ctx)
3570 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3571 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3572 int i;
3574 for (i = 0; i < table->rows; ++i) {
3575 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3577 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3578 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3580 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3581 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3583 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3584 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3589 typedef struct {
3590 const char *name;
3591 const char *name_space;
3592 guint32 resolution_scope;
3593 } TypeDefUniqueId;
3595 static guint
3596 typedef_hash (gconstpointer _key)
3598 const TypeDefUniqueId *key = _key;
3599 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3602 static gboolean
3603 typedef_equals (gconstpointer _a, gconstpointer _b)
3605 const TypeDefUniqueId *a = _a;
3606 const TypeDefUniqueId *b = _b;
3607 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3610 static void
3611 verify_typedef_table_global_constraints (VerifyContext *ctx)
3613 int i;
3614 guint32 data [MONO_TYPEDEF_SIZE];
3615 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3616 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3617 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3618 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3620 for (i = 0; i < table->rows; ++i) {
3621 guint visibility;
3622 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3623 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3625 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3626 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3627 type->resolution_scope = 0;
3629 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3630 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3631 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3632 g_assert (res >= 0);
3634 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3635 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3638 if (g_hash_table_lookup (unique_types, type)) {
3639 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));
3640 g_hash_table_destroy (unique_types);
3641 g_free (type);
3642 return;
3644 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3647 g_hash_table_destroy (unique_types);
3650 static void
3651 verify_typeref_table_global_constraints (VerifyContext *ctx)
3653 int i;
3654 guint32 data [MONO_TYPEREF_SIZE];
3655 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3656 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3658 for (i = 0; i < table->rows; ++i) {
3659 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3660 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3662 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3663 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3664 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3666 if (g_hash_table_lookup (unique_types, type)) {
3667 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));
3668 g_hash_table_destroy (unique_types);
3669 g_free (type);
3670 return;
3672 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3675 g_hash_table_destroy (unique_types);
3678 static void
3679 verify_tables_data_global_constraints (VerifyContext *ctx)
3681 verify_typedef_table_global_constraints (ctx);
3684 static void
3685 verify_tables_data_global_constraints_full (VerifyContext *ctx)
3687 verify_typeref_table_global_constraints (ctx);
3690 static void
3691 verify_tables_data (VerifyContext *ctx)
3693 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3694 guint32 size = 0, tables_offset;
3695 int i;
3697 for (i = 0; i < 0x2D; ++i) {
3698 MonoTableInfo *table = &ctx->image->tables [i];
3699 guint32 tmp_size;
3700 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3701 if (tmp_size < size) {
3702 size = 0;
3703 break;
3705 size = tmp_size;
3708 if (size == 0)
3709 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3711 tables_offset = ctx->image->tables_base - ctx->data;
3712 if (!bounds_check_offset (&tables_area, tables_offset, size))
3713 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)));
3715 verify_module_table (ctx);
3716 CHECK_ERROR ();
3717 verify_typeref_table (ctx);
3718 CHECK_ERROR ();
3719 verify_typedef_table (ctx);
3720 CHECK_ERROR ();
3721 verify_field_table (ctx);
3722 CHECK_ERROR ();
3723 verify_method_table (ctx);
3724 CHECK_ERROR ();
3725 verify_param_table (ctx);
3726 CHECK_ERROR ();
3727 verify_interfaceimpl_table (ctx);
3728 CHECK_ERROR ();
3729 verify_memberref_table (ctx);
3730 CHECK_ERROR ();
3731 verify_constant_table (ctx);
3732 CHECK_ERROR ();
3733 verify_cattr_table (ctx);
3734 CHECK_ERROR ();
3735 verify_field_marshal_table (ctx);
3736 CHECK_ERROR ();
3737 verify_decl_security_table (ctx);
3738 CHECK_ERROR ();
3739 verify_class_layout_table (ctx);
3740 CHECK_ERROR ();
3741 verify_field_layout_table (ctx);
3742 CHECK_ERROR ();
3743 verify_standalonesig_table (ctx);
3744 CHECK_ERROR ();
3745 verify_eventmap_table (ctx);
3746 CHECK_ERROR ();
3747 verify_event_table (ctx);
3748 CHECK_ERROR ();
3749 verify_propertymap_table (ctx);
3750 CHECK_ERROR ();
3751 verify_property_table (ctx);
3752 CHECK_ERROR ();
3753 verify_methodimpl_table (ctx);
3754 CHECK_ERROR ();
3755 verify_moduleref_table (ctx);
3756 CHECK_ERROR ();
3757 verify_typespec_table (ctx);
3758 CHECK_ERROR ();
3759 verify_implmap_table (ctx);
3760 CHECK_ERROR ();
3761 verify_fieldrva_table (ctx);
3762 CHECK_ERROR ();
3763 verify_assembly_table (ctx);
3764 CHECK_ERROR ();
3765 verify_assemblyref_table (ctx);
3766 CHECK_ERROR ();
3767 verify_file_table (ctx);
3768 CHECK_ERROR ();
3769 verify_exportedtype_table (ctx);
3770 CHECK_ERROR ();
3771 verify_manifest_resource_table (ctx);
3772 CHECK_ERROR ();
3773 verify_nested_class_table (ctx);
3774 CHECK_ERROR ();
3775 verify_generic_param_table (ctx);
3776 CHECK_ERROR ();
3777 verify_method_spec_table (ctx);
3778 CHECK_ERROR ();
3779 verify_generic_param_constraint_table (ctx);
3780 CHECK_ERROR ();
3781 verify_tables_data_global_constraints (ctx);
3784 static void
3785 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
3787 memset (ctx, 0, sizeof (VerifyContext));
3788 ctx->image = image;
3789 ctx->report_error = error_list != NULL;
3790 ctx->report_warning = FALSE; //export this setting in the API
3791 ctx->valid = 1;
3792 ctx->size = image->raw_data_len;
3793 ctx->data = image->raw_data;
3796 static gboolean
3797 cleanup_context (VerifyContext *ctx, GSList **error_list)
3799 g_free (ctx->sections);
3800 if (error_list)
3801 *error_list = ctx->errors;
3802 else
3803 mono_free_verify_list (ctx->errors);
3804 return ctx->valid;
3807 gboolean
3808 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3810 VerifyContext ctx;
3812 if (!mono_verifier_is_enabled_for_image (image))
3813 return TRUE;
3815 init_verify_context (&ctx, image, error_list);
3816 ctx.stage = STAGE_PE;
3818 verify_msdos_header (&ctx);
3819 CHECK_STATE();
3820 verify_pe_header (&ctx);
3821 CHECK_STATE();
3822 verify_pe_optional_header (&ctx);
3823 CHECK_STATE();
3824 load_section_table (&ctx);
3825 CHECK_STATE();
3826 load_data_directories (&ctx);
3827 CHECK_STATE();
3828 verify_import_table (&ctx);
3829 CHECK_STATE();
3830 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3831 verify_resources_table (&ctx);
3833 cleanup:
3834 return cleanup_context (&ctx, error_list);
3837 gboolean
3838 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3840 VerifyContext ctx;
3842 if (!mono_verifier_is_enabled_for_image (image))
3843 return TRUE;
3845 init_verify_context (&ctx, image, error_list);
3846 ctx.stage = STAGE_CLI;
3848 verify_cli_header (&ctx);
3849 CHECK_STATE();
3850 verify_metadata_header (&ctx);
3851 CHECK_STATE();
3852 verify_tables_schema (&ctx);
3854 cleanup:
3855 return cleanup_context (&ctx, error_list);
3860 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3861 * Other verification checks are meant to be done lazily by the runtime. Those include:
3862 * blob items (signatures, method headers, custom attributes, etc)
3863 * type semantics related
3864 * vtable related
3865 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3867 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3868 * operation still need more checking.
3870 gboolean
3871 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3873 VerifyContext ctx;
3875 if (!mono_verifier_is_enabled_for_image (image))
3876 return TRUE;
3878 init_verify_context (&ctx, image, error_list);
3879 ctx.stage = STAGE_TABLES;
3881 verify_tables_data (&ctx);
3883 return cleanup_context (&ctx, error_list);
3888 * Verifies all other constraints.
3890 gboolean
3891 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3893 VerifyContext ctx;
3895 if (!mono_verifier_is_enabled_for_image (image))
3896 return TRUE;
3898 init_verify_context (&ctx, image, error_list);
3899 ctx.stage = STAGE_TABLES;
3901 verify_typedef_table_full (&ctx);
3902 CHECK_STATE ();
3903 verify_field_table_full (&ctx);
3904 CHECK_STATE ();
3905 verify_method_table_full (&ctx);
3906 CHECK_STATE ();
3907 verify_memberref_table_full (&ctx);
3908 CHECK_STATE ();
3909 verify_cattr_table_full (&ctx);
3910 CHECK_STATE ();
3911 verify_field_marshal_table_full (&ctx);
3912 CHECK_STATE ();
3913 verify_decl_security_table_full (&ctx);
3914 CHECK_STATE ();
3915 verify_standalonesig_table_full (&ctx);
3916 CHECK_STATE ();
3917 verify_event_table_full (&ctx);
3918 CHECK_STATE ();
3919 verify_typespec_table_full (&ctx);
3920 CHECK_STATE ();
3921 verify_method_spec_table_full (&ctx);
3922 CHECK_STATE ();
3923 verify_tables_data_global_constraints_full (&ctx);
3925 cleanup:
3926 return cleanup_context (&ctx, error_list);
3929 gboolean
3930 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3932 VerifyContext ctx;
3934 if (!mono_verifier_is_enabled_for_image (image))
3935 return TRUE;
3937 init_verify_context (&ctx, image, error_list);
3938 ctx.stage = STAGE_TABLES;
3940 is_valid_field_signature (&ctx, offset);
3941 return cleanup_context (&ctx, error_list);
3944 gboolean
3945 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3947 VerifyContext ctx;
3949 if (!mono_verifier_is_enabled_for_image (image))
3950 return TRUE;
3952 init_verify_context (&ctx, image, error_list);
3953 ctx.stage = STAGE_TABLES;
3955 is_valid_method_header (&ctx, offset);
3956 return cleanup_context (&ctx, error_list);
3959 gboolean
3960 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3962 VerifyContext ctx;
3964 if (!mono_verifier_is_enabled_for_image (image))
3965 return TRUE;
3967 init_verify_context (&ctx, image, error_list);
3968 ctx.stage = STAGE_TABLES;
3970 is_valid_method_signature (&ctx, offset);
3971 return cleanup_context (&ctx, error_list);
3974 gboolean
3975 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3977 VerifyContext ctx;
3979 if (!mono_verifier_is_enabled_for_image (image))
3980 return TRUE;
3982 init_verify_context (&ctx, image, error_list);
3983 ctx.stage = STAGE_TABLES;
3985 is_valid_method_or_field_signature (&ctx, offset);
3986 return cleanup_context (&ctx, error_list);
3989 gboolean
3990 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3992 VerifyContext ctx;
3994 if (!mono_verifier_is_enabled_for_image (image))
3995 return TRUE;
3997 init_verify_context (&ctx, image, error_list);
3998 ctx.stage = STAGE_TABLES;
4000 is_valid_standalonesig_blob (&ctx, offset);
4001 return cleanup_context (&ctx, error_list);
4004 gboolean
4005 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4007 VerifyContext ctx;
4009 if (!mono_verifier_is_enabled_for_image (image))
4010 return TRUE;
4012 init_verify_context (&ctx, image, error_list);
4013 ctx.stage = STAGE_TABLES;
4014 ctx.token = token;
4016 is_valid_typespec_blob (&ctx, offset);
4017 return cleanup_context (&ctx, error_list);
4020 gboolean
4021 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4023 VerifyContext ctx;
4025 if (!mono_verifier_is_enabled_for_image (image))
4026 return TRUE;
4028 init_verify_context (&ctx, image, error_list);
4029 ctx.stage = STAGE_TABLES;
4031 is_valid_methodspec_blob (&ctx, offset);
4032 return cleanup_context (&ctx, error_list);
4035 static void
4036 verify_user_string (VerifyContext *ctx, guint32 offset)
4038 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
4039 guint32 entry_size, bytes;
4041 if (heap_us.size < offset)
4042 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
4044 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
4045 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
4047 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
4048 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
4050 entry_size += bytes;
4052 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
4053 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
4056 gboolean
4057 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4059 VerifyContext ctx;
4061 if (!mono_verifier_is_enabled_for_image (image))
4062 return TRUE;
4064 init_verify_context (&ctx, image, error_list);
4065 ctx.stage = STAGE_TABLES;
4067 verify_user_string (&ctx, offset);
4069 return cleanup_context (&ctx, error_list);
4072 gboolean
4073 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4075 VerifyContext ctx;
4077 if (!mono_verifier_is_enabled_for_image (image))
4078 return TRUE;
4080 init_verify_context (&ctx, image, error_list);
4081 ctx.stage = STAGE_TABLES;
4083 is_valid_cattr_blob (&ctx, offset);
4085 return cleanup_context (&ctx, error_list);
4088 gboolean
4089 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4091 VerifyContext ctx;
4093 if (!mono_verifier_is_enabled_for_image (image))
4094 return TRUE;
4096 init_verify_context (&ctx, image, error_list);
4097 ctx.stage = STAGE_TABLES;
4099 is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
4101 return cleanup_context (&ctx, error_list);
4104 gboolean
4105 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4107 MonoMethodSignature *original_sig;
4108 if (!mono_verifier_is_enabled_for_image (image))
4109 return TRUE;
4111 original_sig = mono_method_signature (method);
4112 if (original_sig->call_convention == MONO_CALL_VARARG) {
4113 if (original_sig->hasthis != signature->hasthis)
4114 return FALSE;
4115 if (original_sig->call_convention != signature->call_convention)
4116 return FALSE;
4117 if (original_sig->explicit_this != signature->explicit_this)
4118 return FALSE;
4119 if (original_sig->call_convention != signature->call_convention)
4120 return FALSE;
4121 if (original_sig->pinvoke != signature->pinvoke)
4122 return FALSE;
4123 if (original_sig->sentinelpos != signature->sentinelpos)
4124 return FALSE;
4125 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4126 return FALSE;
4129 return TRUE;
4132 #else
4133 gboolean
4134 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4136 return TRUE;
4139 gboolean
4140 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
4142 return TRUE;
4145 gboolean
4146 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
4148 return TRUE;
4151 gboolean
4152 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4154 return TRUE;
4157 gboolean
4158 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4160 return TRUE;
4163 gboolean
4164 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4166 return TRUE;
4169 gboolean
4170 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4172 return TRUE;
4175 gboolean
4176 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
4178 return TRUE;
4181 gboolean
4182 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4184 return TRUE;
4187 gboolean
4188 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4190 return TRUE;
4193 gboolean
4194 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4196 return TRUE;
4199 gboolean
4200 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4202 return TRUE;
4205 gboolean
4206 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4208 return TRUE;
4211 gboolean
4212 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4214 return TRUE;
4217 gboolean
4218 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4220 return TRUE;
4224 #endif /* DISABLE_VERIFIER */