Bump version to 2.7.1
[mono-project/dkf.git] / mono / metadata / metadata-verify.c
blob157ad76f97721dfe02fe36b00d598582808c28ea
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 <mono/utils/mono-error-internals.h>
27 #include <string.h>
28 //#include <signal.h>
29 #include <ctype.h>
31 #ifndef DISABLE_VERIFIER
33 TODO add fail fast mode
34 TODO add PE32+ support
35 TODO verify the entry point RVA and content.
36 TODO load_section_table and load_data_directories must take PE32+ into account
37 TODO add section relocation support
38 TODO verify the relocation table, since we really don't use, no need so far.
39 TODO do full PECOFF resources verification
40 TODO verify in the CLI header entry point and resources
41 TODO implement null token typeref validation
42 TODO verify table wide invariants for typedef (sorting and uniqueness)
43 TODO implement proper authenticode data directory validation
44 TODO verify properties that require multiple tables to be valid
45 FIXME use subtraction based bounds checking to avoid overflows
46 FIXME get rid of metadata_streams and other fields from VerifyContext
49 #ifdef MONO_VERIFIER_DEBUG
50 #define VERIFIER_DEBUG(code) do { code; } while (0)
51 #else
52 #define VERIFIER_DEBUG(code)
53 #endif
55 #define INVALID_OFFSET ((guint32)-1)
56 #define INVALID_ADDRESS 0xffffffff
58 enum {
59 STAGE_PE,
60 STAGE_CLI,
61 STAGE_TABLES
64 enum {
65 IMPORT_TABLE_IDX = 1,
66 RESOURCE_TABLE_IDX = 2,
67 CERTIFICATE_TABLE_IDX = 4,
68 RELOCATION_TABLE_IDX = 5,
69 IAT_IDX = 12,
70 CLI_HEADER_IDX = 14,
73 enum {
74 STRINGS_STREAM,
75 USER_STRINGS_STREAM,
76 BLOB_STREAM,
77 GUID_STREAM,
78 TILDE_STREAM
82 #define INVALID_TABLE (0xFF)
83 /*format: number of bits, number of tables, tables{n. tables} */
84 const static unsigned char coded_index_desc[] = {
85 #define TYPEDEF_OR_REF_DESC (0)
86 2, /*bits*/
87 3, /*tables*/
88 MONO_TABLE_TYPEDEF,
89 MONO_TABLE_TYPEREF,
90 MONO_TABLE_TYPESPEC,
92 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
93 2, /*bits*/
94 3, /*tables*/
95 MONO_TABLE_FIELD,
96 MONO_TABLE_PARAM,
97 MONO_TABLE_PROPERTY,
99 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
100 5, /*bits*/
101 20, /*tables*/
102 MONO_TABLE_METHOD,
103 MONO_TABLE_FIELD,
104 MONO_TABLE_TYPEREF,
105 MONO_TABLE_TYPEDEF,
106 MONO_TABLE_PARAM,
107 MONO_TABLE_INTERFACEIMPL,
108 MONO_TABLE_MEMBERREF,
109 MONO_TABLE_MODULE,
110 MONO_TABLE_DECLSECURITY,
111 MONO_TABLE_PROPERTY,
112 MONO_TABLE_EVENT,
113 MONO_TABLE_STANDALONESIG,
114 MONO_TABLE_MODULEREF,
115 MONO_TABLE_TYPESPEC,
116 MONO_TABLE_ASSEMBLY,
117 MONO_TABLE_ASSEMBLYREF,
118 MONO_TABLE_FILE,
119 MONO_TABLE_EXPORTEDTYPE,
120 MONO_TABLE_MANIFESTRESOURCE,
121 MONO_TABLE_GENERICPARAM,
123 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
124 1, /*bits*/
125 2, /*tables*/
126 MONO_TABLE_FIELD,
127 MONO_TABLE_PARAM,
129 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
130 2, /*bits*/
131 3, /*tables*/
132 MONO_TABLE_TYPEDEF,
133 MONO_TABLE_METHOD,
134 MONO_TABLE_ASSEMBLY,
136 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
137 3, /*bits*/
138 5, /*tables*/
139 MONO_TABLE_TYPEDEF,
140 MONO_TABLE_TYPEREF,
141 MONO_TABLE_MODULE,
142 MONO_TABLE_METHOD,
143 MONO_TABLE_TYPESPEC,
145 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
146 1, /*bits*/
147 2, /*tables*/
148 MONO_TABLE_EVENT,
149 MONO_TABLE_PROPERTY,
151 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
152 1, /*bits*/
153 2, /*tables*/
154 MONO_TABLE_METHOD,
155 MONO_TABLE_MEMBERREF,
157 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
158 1, /*bits*/
159 2, /*tables*/
160 MONO_TABLE_FIELD,
161 MONO_TABLE_METHOD,
163 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
164 2, /*bits*/
165 3, /*tables*/
166 MONO_TABLE_FILE,
167 MONO_TABLE_ASSEMBLYREF,
168 MONO_TABLE_EXPORTEDTYPE,
170 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
171 3, /*bits*/
172 5, /*tables*/
173 INVALID_TABLE,
174 INVALID_TABLE,
175 MONO_TABLE_METHOD,
176 MONO_TABLE_MEMBERREF,
177 INVALID_TABLE,
179 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
180 2, /*bits*/
181 4, /*tables*/
182 MONO_TABLE_MODULE,
183 MONO_TABLE_MODULEREF,
184 MONO_TABLE_ASSEMBLYREF,
185 MONO_TABLE_TYPEREF,
187 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
188 1, /*bits*/
189 2, /*tables*/
190 MONO_TABLE_TYPEDEF,
191 MONO_TABLE_METHOD
194 typedef struct {
195 guint32 rva;
196 guint32 size;
197 guint32 translated_offset;
198 } DataDirectory;
200 typedef struct {
201 guint32 offset;
202 guint32 size;
203 } OffsetAndSize;
205 typedef struct {
206 guint32 baseRVA;
207 guint32 baseOffset;
208 guint32 size;
209 guint32 rellocationsRVA;
210 guint16 numberOfRelocations;
211 } SectionHeader;
213 typedef struct {
214 guint32 row_count;
215 guint32 row_size;
216 guint32 offset;
217 } TableInfo;
219 typedef struct {
220 const char *data;
221 guint32 size, token;
222 GSList *errors;
223 int valid;
224 MonoImage *image;
225 gboolean report_error;
226 gboolean report_warning;
227 int stage;
229 DataDirectory data_directories [16];
230 guint32 section_count;
231 SectionHeader *sections;
233 OffsetAndSize metadata_streams [5]; //offset from begin of the image
234 } VerifyContext;
236 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
237 do { \
238 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
239 vinfo->info.status = __status; \
240 vinfo->info.message = ( __msg); \
241 vinfo->exception_type = (__exception); \
242 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
243 } while (0)
245 #define ADD_WARNING(__ctx, __msg) \
246 do { \
247 if ((__ctx)->report_warning) { \
248 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
249 (__ctx)->valid = 0; \
250 return; \
252 } while (0)
254 #define ADD_ERROR_NO_RETURN(__ctx, __msg) \
255 do { \
256 if ((__ctx)->report_error) \
257 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
258 (__ctx)->valid = 0; \
259 } while (0)
261 #define ADD_ERROR(__ctx, __msg) \
262 do { \
263 if ((__ctx)->report_error) \
264 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
265 (__ctx)->valid = 0; \
266 return; \
267 } while (0)
269 #define FAIL(__ctx, __msg) \
270 do { \
271 if ((__ctx)->report_error) \
272 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
273 (__ctx)->valid = 0; \
274 return FALSE; \
275 } while (0)
277 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
279 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
281 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
282 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
284 #if SIZEOF_VOID_P == 4
285 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
286 #else
287 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
288 #endif
290 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
291 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
293 static const char *
294 dword_align (const char *ptr)
296 #if SIZEOF_VOID_P == 8
297 return (const char *) (((guint64) (ptr + 3)) & ~3);
298 #else
299 return (const char *) (((guint32) (ptr + 3)) & ~3);
300 #endif
303 static guint32
304 pe_signature_offset (VerifyContext *ctx)
306 return read32 (ctx->data + 0x3c);
309 static guint32
310 pe_header_offset (VerifyContext *ctx)
312 return read32 (ctx->data + 0x3c) + 4;
315 static gboolean
316 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
318 int i;
320 if (rva + size < rva) //overflow
321 return FALSE;
323 if (ctx->stage > STAGE_PE) {
324 MonoCLIImageInfo *iinfo = ctx->image->image_info;
325 const int top = iinfo->cli_section_count;
326 MonoSectionTable *tables = iinfo->cli_section_tables;
327 int i;
329 for (i = 0; i < top; i++) {
330 guint32 base = tables->st_virtual_address;
331 guint32 end = base + tables->st_raw_data_size;
333 if (rva >= base && rva + size <= end)
334 return TRUE;
336 /*if ((addr >= tables->st_virtual_address) &&
337 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
339 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
341 tables++;
343 return FALSE;
346 if (!ctx->sections)
347 return FALSE;
349 for (i = 0; i < ctx->section_count; ++i) {
350 guint32 base = ctx->sections [i].baseRVA;
351 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
352 if (rva >= base && rva + size <= end)
353 return TRUE;
355 return FALSE;
358 static gboolean
359 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
361 if (dir->translated_offset > offset)
362 return FALSE;
363 if (dir->size < size)
364 return FALSE;
365 return offset + size <= dir->translated_offset + dir->size;
368 static gboolean
369 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
371 if (off->offset > offset)
372 return FALSE;
374 if (off->size < size)
375 return FALSE;
377 return offset + size <= off->offset + off->size;
380 static guint32
381 translate_rva (VerifyContext *ctx, guint32 rva)
383 int i;
385 if (ctx->stage > STAGE_PE)
386 return mono_cli_rva_image_map (ctx->image, rva);
388 if (!ctx->sections)
389 return FALSE;
391 for (i = 0; i < ctx->section_count; ++i) {
392 guint32 base = ctx->sections [i].baseRVA;
393 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
394 if (rva >= base && rva <= end) {
395 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
396 /* double check */
397 return res >= ctx->size ? INVALID_OFFSET : res;
401 return INVALID_OFFSET;
404 static void
405 verify_msdos_header (VerifyContext *ctx)
407 guint32 lfanew;
408 if (ctx->size < 128)
409 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
410 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
411 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
412 lfanew = pe_signature_offset (ctx);
413 if (lfanew > ctx->size - 4)
414 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
417 static void
418 verify_pe_header (VerifyContext *ctx)
420 guint32 offset = pe_signature_offset (ctx);
421 const char *pe_header = ctx->data + offset;
422 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
423 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
424 pe_header += 4;
425 offset += 4;
427 if (offset > ctx->size - 20)
428 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
429 if (read16 (pe_header) != 0x14c)
430 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
433 static void
434 verify_pe_optional_header (VerifyContext *ctx)
436 guint32 offset = pe_header_offset (ctx);
437 guint32 header_size, file_alignment;
438 const char *pe_header = ctx->data + offset;
439 const char *pe_optional_header = pe_header + 20;
441 header_size = read16 (pe_header + 16);
442 offset += 20;
444 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
445 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
447 if (offset > ctx->size - header_size || header_size > ctx->size)
448 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
450 if (read16 (pe_optional_header) == 0x10b) {
451 if (header_size != 224)
452 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
454 /* LAMESPEC MS plays around this value and ignore it during validation
455 if (read32 (pe_optional_header + 28) != 0x400000)
456 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
457 if (read32 (pe_optional_header + 32) != 0x2000)
458 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
459 file_alignment = read32 (pe_optional_header + 36);
460 if (file_alignment != 0x200 && file_alignment != 0x1000)
461 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
462 /* All the junk in the middle is irrelevant, specially for mono. */
463 if (read32 (pe_optional_header + 92) > 0x10)
464 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
465 } else {
466 if (read16 (pe_optional_header) == 0x20B)
467 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
468 else
469 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
473 static void
474 load_section_table (VerifyContext *ctx)
476 int i;
477 SectionHeader *sections;
478 guint32 offset = pe_header_offset (ctx);
479 const char *ptr = ctx->data + offset;
480 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
482 offset += 244;/*FIXME, this constant is different under PE32+*/
483 ptr += 244;
485 if (num_sections * 40 > ctx->size - offset)
486 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
488 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
489 for (i = 0; i < num_sections; ++i) {
490 sections [i].size = read32 (ptr + 8);
491 sections [i].baseRVA = read32 (ptr + 12);
492 sections [i].baseOffset = read32 (ptr + 20);
493 sections [i].rellocationsRVA = read32 (ptr + 24);
494 sections [i].numberOfRelocations = read16 (ptr + 32);
495 ptr += 40;
498 ptr = ctx->data + offset; /*reset it to the beggining*/
499 for (i = 0; i < num_sections; ++i) {
500 guint32 raw_size, flags;
501 if (sections [i].baseOffset == 0)
502 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
503 if (sections [i].baseOffset >= ctx->size)
504 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
505 if (sections [i].size > ctx->size - sections [i].baseOffset)
506 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
508 raw_size = read32 (ptr + 16);
509 if (raw_size < sections [i].size)
510 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
512 if (raw_size > ctx->size - sections [i].baseOffset)
513 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
515 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
516 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
518 flags = read32 (ptr + 36);
519 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
520 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
521 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
523 ptr += 40;
527 static gboolean
528 is_valid_data_directory (int i)
530 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
531 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
534 static void
535 load_data_directories (VerifyContext *ctx)
537 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
538 const char *ptr = ctx->data + offset;
539 int i;
541 for (i = 0; i < 16; ++i) {
542 guint32 rva = read32 (ptr);
543 guint32 size = read32 (ptr + 4);
545 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
546 if (i == CERTIFICATE_TABLE_IDX) {
547 ptr += 8;
548 continue;
550 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
551 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
553 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
554 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
556 ctx->data_directories [i].rva = rva;
557 ctx->data_directories [i].size = size;
558 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
560 ptr += 8;
564 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
566 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
568 static void
569 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
571 const char *ptr;
572 guint32 hint_table_rva;
574 import_rva = translate_rva (ctx, import_rva);
575 g_assert (import_rva != INVALID_OFFSET);
577 hint_table_rva = read32 (ctx->data + import_rva);
578 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
579 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
581 hint_table_rva = translate_rva (ctx, hint_table_rva);
582 g_assert (hint_table_rva != INVALID_OFFSET);
583 ptr = ctx->data + hint_table_rva + 2;
585 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
586 char name[SIZE_OF_CORMAIN];
587 memcpy (name, ptr, SIZE_OF_CORMAIN);
588 name [SIZE_OF_CORMAIN - 1] = 0;
589 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
593 static void
594 verify_import_table (VerifyContext *ctx)
596 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
597 guint32 offset = it.translated_offset;
598 const char *ptr = ctx->data + offset;
599 guint32 name_rva, ilt_rva, iat_rva;
601 g_assert (offset != INVALID_OFFSET);
603 if (it.size < 40)
604 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
606 ilt_rva = read32 (ptr);
607 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
608 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
610 name_rva = read32 (ptr + 12);
611 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
612 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
614 iat_rva = read32 (ptr + 16);
615 if (iat_rva) {
616 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
617 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
619 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
620 ADD_ERROR (ctx, g_strdup_printf ("Import Address Table rva %x different from data directory entry %x", read32 (ptr + 16), ctx->data_directories [IAT_IDX].rva));
623 if (name_rva) {
624 name_rva = translate_rva (ctx, name_rva);
625 g_assert (name_rva != INVALID_OFFSET);
626 ptr = ctx->data + name_rva;
628 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
629 char name[SIZE_OF_MSCOREE];
630 memcpy (name, ptr, SIZE_OF_MSCOREE);
631 name [SIZE_OF_MSCOREE - 1] = 0;
632 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
636 if (ilt_rva) {
637 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
638 CHECK_ERROR ();
641 if (iat_rva)
642 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
645 static void
646 verify_resources_table (VerifyContext *ctx)
648 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
649 guint32 offset;
650 guint16 named_entries, id_entries;
651 const char *ptr, *root, *end;
653 if (it.rva == 0)
654 return;
656 if (it.size < 16)
657 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));
659 offset = it.translated_offset;
660 root = ptr = ctx->data + offset;
661 end = root + it.size;
663 g_assert (offset != INVALID_OFFSET);
665 named_entries = read16 (ptr + 12);
666 id_entries = read16 (ptr + 14);
668 if ((named_entries + id_entries) * 8 + 16 > it.size)
669 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));
671 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
672 if (named_entries || id_entries)
673 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
677 /*----------nothing from here on can use data_directory---*/
679 static DataDirectory
680 get_data_dir (VerifyContext *ctx, int idx)
682 MonoCLIImageInfo *iinfo = ctx->image->image_info;
683 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
684 DataDirectory res;
686 entry += idx;
687 res.rva = entry->rva;
688 res.size = entry->size;
689 res.translated_offset = translate_rva (ctx, res.rva);
690 return res;
693 static void
694 verify_cli_header (VerifyContext *ctx)
696 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
697 guint32 offset;
698 const char *ptr;
699 int i;
701 if (it.rva == 0)
702 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
704 if (it.size != 72)
705 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
707 offset = it.translated_offset;
708 ptr = ctx->data + offset;
710 g_assert (offset != INVALID_OFFSET);
712 if (read16 (ptr) != 72)
713 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
715 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
716 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
719 if (!read32 (ptr + 8) || !read32 (ptr + 12))
720 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
722 if ((read32 (ptr + 16) & ~0x0001000B) != 0)
723 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
725 ptr += 24;
726 for (i = 0; i < 6; ++i) {
727 guint32 rva = read32 (ptr);
728 guint32 size = read32 (ptr + 4);
730 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
731 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
733 ptr += 8;
735 if (rva && i > 1)
736 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
740 static guint32
741 pad4 (guint32 offset)
743 if (offset & 0x3) //pad to the next 4 byte boundary
744 offset = (offset & ~0x3) + 4;
745 return offset;
748 static void
749 verify_metadata_header (VerifyContext *ctx)
751 int i;
752 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
753 guint32 offset, section_count;
754 const char *ptr;
756 offset = it.translated_offset;
757 ptr = ctx->data + offset;
758 g_assert (offset != INVALID_OFFSET);
760 //build a directory entry for the metadata root
761 ptr += 8;
762 it.rva = read32 (ptr);
763 ptr += 4;
764 it.size = read32 (ptr);
765 it.translated_offset = offset = translate_rva (ctx, it.rva);
767 ptr = ctx->data + offset;
768 g_assert (offset != INVALID_OFFSET);
770 if (it.size < 20)
771 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
773 if (read32 (ptr) != 0x424A5342)
774 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
776 offset = pad4 (offset + 16 + read32 (ptr + 12));
778 if (!bounds_check_datadir (&it, offset, 4))
779 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));
781 ptr = ctx->data + offset; //move to streams header
783 section_count = read16 (ptr + 2);
784 if (section_count < 2)
785 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 2 streams (#~ and #GUID)"));
787 ptr += 4;
788 offset += 4;
790 for (i = 0; i < section_count; ++i) {
791 guint32 stream_off, stream_size;
792 int string_size, stream_idx;
794 if (!bounds_check_datadir (&it, offset, 8))
795 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));
797 stream_off = it.translated_offset + read32 (ptr);
798 stream_size = read32 (ptr + 4);
800 if (!bounds_check_datadir (&it, stream_off, stream_size))
801 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
803 ptr += 8;
804 offset += 8;
806 for (string_size = 0; string_size < 32; ++string_size) {
807 if (!bounds_check_datadir (&it, offset++, 1))
808 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
809 if (!ptr [string_size])
810 break;
813 if (ptr [string_size])
814 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
816 if (!strncmp ("#Strings", ptr, 9))
817 stream_idx = STRINGS_STREAM;
818 else if (!strncmp ("#US", ptr, 4))
819 stream_idx = USER_STRINGS_STREAM;
820 else if (!strncmp ("#Blob", ptr, 6))
821 stream_idx = BLOB_STREAM;
822 else if (!strncmp ("#GUID", ptr, 6))
823 stream_idx = GUID_STREAM;
824 else if (!strncmp ("#~", ptr, 3))
825 stream_idx = TILDE_STREAM;
826 else {
827 ADD_WARNING (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
828 offset = pad4 (offset);
829 ptr = ctx->data + offset;
830 continue;
833 if (ctx->metadata_streams [stream_idx].offset != 0)
834 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
836 ctx->metadata_streams [stream_idx].offset = stream_off;
837 ctx->metadata_streams [stream_idx].size = stream_size;
839 offset = pad4 (offset);
840 ptr = ctx->data + offset;
843 if (!ctx->metadata_streams [TILDE_STREAM].size)
844 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
845 if (!ctx->metadata_streams [GUID_STREAM].size)
846 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
849 static void
850 verify_tables_schema (VerifyContext *ctx)
852 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
853 unsigned offset = tables_area.offset;
854 const char *ptr = ctx->data + offset;
855 guint64 valid_tables;
856 guint32 count;
857 int i;
859 if (tables_area.size < 24)
860 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
862 if (ptr [4] != 2 && ptr [4] != 1)
863 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
864 if (ptr [5] != 0)
865 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
867 if ((ptr [6] & ~0x7) != 0)
868 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]));
870 valid_tables = read64 (ptr + 8);
871 count = 0;
872 for (i = 0; i < 64; ++i) {
873 if (!(valid_tables & ((guint64)1 << i)))
874 continue;
876 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
877 Unused: 0x1E 0x1F 0x2D-0x3F
878 We don't care about the MS extensions.*/
879 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
880 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i));
881 if (i == 0x1E || i == 0x1F || i >= 0x2D)
882 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
883 ++count;
886 if (tables_area.size < 24 + count * 4)
887 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));
888 ptr += 24;
890 for (i = 0; i < 64; ++i) {
891 if (valid_tables & ((guint64)1 << i)) {
892 guint32 row_count = read32 (ptr);
893 if (row_count > (1 << 24) - 1)
894 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
895 ptr += 4;
900 /*----------nothing from here on can use data_directory or metadata_streams ---*/
902 static guint32
903 get_col_offset (VerifyContext *ctx, int table, int column)
905 guint32 bitfield = ctx->image->tables [table].size_bitfield;
906 guint32 offset = 0;
908 while (column-- > 0)
909 offset += mono_metadata_table_size (bitfield, column);
911 return offset;
914 static guint32
915 get_col_size (VerifyContext *ctx, int table, int column)
917 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
920 static OffsetAndSize
921 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
923 OffsetAndSize res;
924 res.offset = header->data - ctx->data;
925 res.size = header->size;
927 return res;
930 static gboolean
931 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
933 OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
934 glong length;
935 const char *data = ctx->data + strings.offset;
937 if (offset >= strings.size)
938 return FALSE;
939 if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing
940 return FALSE;
942 if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
943 return FALSE;
944 return allow_empty || length > 0;
947 static gboolean
948 is_valid_string (VerifyContext *ctx, guint32 offset)
950 return is_valid_string_full (ctx, offset, TRUE);
953 static gboolean
954 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
956 return is_valid_string_full (ctx, offset, FALSE);
959 static gboolean
960 is_valid_guid (VerifyContext *ctx, guint32 offset)
962 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
963 return guids.size >= 8 && guids.size - 8 >= offset;
966 static guint32
967 get_coded_index_token (int token_kind, guint32 coded_token)
969 guint32 bits = coded_index_desc [token_kind];
970 return coded_token >> bits;
973 static guint32
974 get_coded_index_table (int kind, guint32 coded_token)
976 guint32 idx, bits = coded_index_desc [kind];
977 kind += 2;
978 idx = coded_token & ((1 << bits) - 1);
979 return coded_index_desc [kind + idx];
982 static guint32
983 make_coded_token (int kind, guint32 table, guint32 table_idx)
985 guint32 bits = coded_index_desc [kind++];
986 guint32 tables = coded_index_desc [kind++];
987 guint32 i;
988 for (i = 0; i < tables; ++i) {
989 if (coded_index_desc [kind++] == table)
990 return ((table_idx + 1) << bits) | i;
992 g_assert_not_reached ();
993 return -1;
996 static gboolean
997 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
999 guint32 bits = coded_index_desc [token_kind++];
1000 guint32 table_count = coded_index_desc [token_kind++];
1001 guint32 table = coded_token & ((1 << bits) - 1);
1002 guint32 token = coded_token >> bits;
1004 if (table >= table_count)
1005 return FALSE;
1007 /*token_kind points to the first table idx*/
1008 table = coded_index_desc [token_kind + table];
1010 if (table == INVALID_TABLE)
1011 return FALSE;
1012 return token <= ctx->image->tables [table].rows;
1015 typedef struct {
1016 guint32 token;
1017 guint32 col_size;
1018 guint32 col_offset;
1019 MonoTableInfo *table;
1020 } RowLocator;
1022 static int
1023 token_locator (const void *a, const void *b)
1025 RowLocator *loc = (RowLocator *)a;
1026 unsigned const char *row = (unsigned const char *)b;
1027 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1029 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1030 return (int)loc->token - (int)token;
1033 static int
1034 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1036 MonoTableInfo *tinfo = &ctx->image->tables [table];
1037 RowLocator locator;
1038 const char *res, *base;
1039 locator.token = coded_token;
1040 locator.col_offset = get_col_offset (ctx, table, column);
1041 locator.col_size = get_col_size (ctx, table, column);
1042 locator.table = tinfo;
1044 base = tinfo->base;
1046 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) );
1047 res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1048 if (!res)
1049 return -1;
1051 return (res - base) / tinfo->row_size;
1054 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1055 static const char*
1056 get_string_ptr (VerifyContext *ctx, guint offset)
1058 return ctx->image->heap_strings.data + offset;
1061 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1062 static int
1063 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1065 if (offset == 0)
1066 return strcmp (str, "");
1068 return strcmp (str, get_string_ptr (ctx, offset));
1071 static gboolean
1072 mono_verifier_is_corlib (MonoImage *image)
1074 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
1075 TRUE : mono_security_core_clr_is_platform_image (image);
1077 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1080 static gboolean
1081 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1083 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1086 static gboolean
1087 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1089 unsigned char b;
1090 const unsigned char *ptr = (const unsigned char *)_ptr;
1092 if (!available)
1093 return FALSE;
1095 b = *ptr;
1096 *value = *size = 0;
1098 if ((b & 0x80) == 0) {
1099 *size = 1;
1100 *value = b;
1101 } else if ((b & 0x40) == 0) {
1102 if (available < 2)
1103 return FALSE;
1104 *size = 2;
1105 *value = ((b & 0x3f) << 8 | ptr [1]);
1106 } else {
1107 if (available < 4)
1108 return FALSE;
1109 *size = 4;
1110 *value = ((b & 0x1f) << 24) |
1111 (ptr [1] << 16) |
1112 (ptr [2] << 8) |
1113 ptr [3];
1116 return TRUE;
1119 static gboolean
1120 decode_signature_header (VerifyContext *ctx, guint32 offset, guint32 *size, const char **first_byte)
1122 MonoStreamHeader blob = ctx->image->heap_blob;
1123 guint32 value, enc_size;
1125 if (offset >= blob.size)
1126 return FALSE;
1128 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1129 return FALSE;
1131 if (CHECK_ADD4_OVERFLOW_UN (offset, enc_size))
1132 return FALSE;
1134 offset += enc_size;
1136 if (ADD_IS_GREATER_OR_OVF (offset, value, blob.size))
1137 return FALSE;
1139 *size = value;
1140 *first_byte = blob.data + offset;
1141 return TRUE;
1144 static gboolean
1145 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1147 const char *ptr = *_ptr;
1148 if (ptr + size > limit)
1149 return FALSE;
1150 switch (size) {
1151 case 1:
1152 *dest = *((guint8*)ptr);
1153 ++ptr;
1154 break;
1155 case 2:
1156 *dest = read16 (ptr);
1157 ptr += 2;
1158 break;
1159 case 4:
1160 *dest = read32 (ptr);
1161 ptr += 4;
1162 break;
1164 *_ptr = ptr;
1165 return TRUE;
1168 static gboolean
1169 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1171 unsigned size = 0;
1172 const char *ptr = *_ptr;
1173 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1174 *_ptr = ptr + size;
1175 return res;
1178 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1179 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1180 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1181 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1183 static gboolean
1184 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1186 static gboolean
1187 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1189 static gboolean
1190 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1192 const char *ptr = *_ptr;
1193 unsigned type = 0;
1194 unsigned token = 0;
1196 while (TRUE) {
1197 if (!safe_read8 (type, ptr, end))
1198 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1200 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1201 --ptr;
1202 break;
1205 if (!safe_read_cint (token, ptr, end))
1206 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1208 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1209 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1212 *_ptr = ptr;
1213 return TRUE;
1216 static gboolean
1217 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1219 const char *ptr = *_ptr;
1220 unsigned val = 0;
1221 unsigned size, num, i;
1223 if (!safe_read8 (val, ptr, end))
1224 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1226 if (val == 0)
1227 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1229 if (!safe_read_cint (size, ptr, end))
1230 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1232 for (i = 0; i < size; ++i) {
1233 if (!safe_read_cint (num, ptr, end))
1234 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1237 if (!safe_read_cint (size, ptr, end))
1238 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1240 for (i = 0; i < size; ++i) {
1241 if (!safe_read_cint (num, ptr, end))
1242 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1245 *_ptr = ptr;
1246 return TRUE;
1249 static gboolean
1250 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1252 const char *ptr = *_ptr;
1253 unsigned type;
1254 unsigned count, token, i;
1256 if (!safe_read8 (type, ptr, end))
1257 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1259 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1260 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1262 if (!safe_read_cint (token, ptr, end))
1263 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1265 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1266 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1268 if (ctx->token) {
1269 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1270 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1271 FAIL (ctx, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx->token));
1274 if (!safe_read_cint (count, ptr, end))
1275 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1277 if (count == 0)
1278 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1280 for (i = 0; i < count; ++i) {
1281 if (!parse_type (ctx, &ptr, end))
1282 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1284 *_ptr = ptr;
1285 return TRUE;
1288 static gboolean
1289 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1291 const char *ptr = *_ptr;
1292 unsigned type;
1293 unsigned token = 0;
1295 if (!safe_read8 (type, ptr, end))
1296 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1298 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1299 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1300 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1301 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1302 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1304 switch (type) {
1305 case MONO_TYPE_PTR:
1306 if (!parse_custom_mods (ctx, &ptr, end))
1307 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1309 if (!safe_read8 (type, ptr, end))
1310 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1312 if (type != MONO_TYPE_VOID) {
1313 --ptr;
1314 if (!parse_type (ctx, &ptr, end))
1315 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1317 break;
1319 case MONO_TYPE_VALUETYPE:
1320 case MONO_TYPE_CLASS:
1321 if (!safe_read_cint (token, ptr, end))
1322 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1324 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1325 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1326 if (ctx->token) {
1327 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1328 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1329 FAIL (ctx, g_strdup_printf ("Type: Recurside type specification (%x). A type signature can't reference itself", ctx->token));
1331 break;
1333 case MONO_TYPE_VAR:
1334 case MONO_TYPE_MVAR:
1335 if (!safe_read_cint (token, ptr, end))
1336 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1337 break;
1339 case MONO_TYPE_ARRAY:
1340 if (!parse_type (ctx, &ptr, end))
1341 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1342 if (!parse_array_shape (ctx, &ptr, end))
1343 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1344 break;
1346 case MONO_TYPE_GENERICINST:
1347 if (!parse_generic_inst (ctx, &ptr, end))
1348 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1349 break;
1351 case MONO_TYPE_FNPTR:
1352 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1353 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1354 break;
1356 case MONO_TYPE_SZARRAY:
1357 if (!parse_custom_mods (ctx, &ptr, end))
1358 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1359 if (!parse_type (ctx, &ptr, end))
1360 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1361 break;
1363 *_ptr = ptr;
1364 return TRUE;
1367 static gboolean
1368 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1370 const char *ptr;
1371 unsigned type = 0;
1373 if (!parse_custom_mods (ctx, _ptr, end))
1374 return FALSE;
1376 ptr = *_ptr;
1377 if (!safe_read8 (type, ptr, end))
1378 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1380 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1381 *_ptr = ptr;
1382 return TRUE;
1385 //it's a byref, update the cursor ptr
1386 if (type == MONO_TYPE_BYREF)
1387 *_ptr = ptr;
1389 return parse_type (ctx, _ptr, end);
1392 static gboolean
1393 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1395 const char *ptr;
1396 unsigned type = 0;
1398 if (!parse_custom_mods (ctx, _ptr, end))
1399 return FALSE;
1401 ptr = *_ptr;
1402 if (!safe_read8 (type, ptr, end))
1403 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1405 if (type == MONO_TYPE_TYPEDBYREF) {
1406 *_ptr = ptr;
1407 return TRUE;
1410 //it's a byref, update the cursor ptr
1411 if (type == MONO_TYPE_BYREF)
1412 *_ptr = ptr;
1414 return parse_type (ctx, _ptr, end);
1417 static gboolean
1418 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1420 unsigned cconv = 0;
1421 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1422 const char *ptr = *_ptr;
1423 gboolean saw_sentinel = FALSE;
1425 if (!safe_read8 (cconv, ptr, end))
1426 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1428 if (cconv & 0x80)
1429 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1431 if (allow_unmanaged) {
1432 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1433 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1434 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1435 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1437 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1438 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1440 if ((cconv & 0x10) && gparam_count == 0)
1441 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1443 if (allow_unmanaged && (cconv & 0x10))
1444 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1446 if (!safe_read_cint (param_count, ptr, end))
1447 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1449 if (!parse_return_type (ctx, &ptr, end))
1450 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1452 for (i = 0; i < param_count; ++i) {
1453 if (allow_sentinel) {
1454 if (!safe_read8 (type, ptr, end))
1455 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1457 if (type == MONO_TYPE_SENTINEL) {
1458 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1459 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1461 if (saw_sentinel)
1462 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1464 saw_sentinel = TRUE;
1465 } else {
1466 --ptr;
1470 if (!parse_param (ctx, &ptr, end))
1471 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1474 *_ptr = ptr;
1475 return TRUE;
1478 static gboolean
1479 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1481 unsigned sig = 0;
1482 unsigned param_count = 0, i;
1483 const char *ptr = *_ptr;
1485 if (!safe_read8 (sig, ptr, end))
1486 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1488 if (sig != 0x08 && sig != 0x28)
1489 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1491 if (!safe_read_cint (param_count, ptr, end))
1492 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1494 if (!parse_custom_mods (ctx, &ptr, end))
1495 return FALSE;
1497 if (!parse_type (ctx, &ptr, end))
1498 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1500 for (i = 0; i < param_count; ++i) {
1501 if (!parse_type (ctx, &ptr, end))
1502 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1505 *_ptr = ptr;
1506 return TRUE;
1509 static gboolean
1510 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1512 const char *ptr = *_ptr;
1513 unsigned signature = 0;
1515 if (!safe_read8 (signature, ptr, end))
1516 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1518 if (signature != 0x06)
1519 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1521 if (!parse_custom_mods (ctx, &ptr, end))
1522 return FALSE;
1524 if (safe_read8 (signature, ptr, end)) {
1525 if (signature != MONO_TYPE_BYREF)
1526 --ptr;
1528 *_ptr = ptr;
1530 return parse_type (ctx, _ptr, end);
1533 static gboolean
1534 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1536 unsigned sig = 0;
1537 unsigned locals_count = 0, i;
1538 const char *ptr = *_ptr;
1540 if (!safe_read8 (sig, ptr, end))
1541 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1543 if (sig != 0x07)
1544 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1546 if (!safe_read_cint (locals_count, ptr, end))
1547 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1549 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1550 if (locals_count == 0)
1551 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1554 for (i = 0; i < locals_count; ++i) {
1555 if (!safe_read8 (sig, ptr, end))
1556 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1558 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1559 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1560 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1561 if (!safe_read8 (sig, ptr, end))
1562 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1565 if (sig == MONO_TYPE_BYREF) {
1566 if (!safe_read8 (sig, ptr, end))
1567 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1568 if (sig == MONO_TYPE_TYPEDBYREF)
1569 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1572 if (sig == MONO_TYPE_TYPEDBYREF)
1573 continue;
1575 --ptr;
1577 if (!parse_type (ctx, &ptr, end))
1578 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1581 *_ptr = ptr;
1582 return TRUE;
1585 static gboolean
1586 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1588 guint32 size = 0;
1589 unsigned signature = 0;
1590 const char *ptr = NULL, *end;
1592 if (!decode_signature_header (ctx, offset, &size, &ptr))
1593 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1594 end = ptr + size;
1596 if (!safe_read8 (signature, ptr, end))
1597 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1599 if (signature != 6)
1600 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1601 --ptr;
1603 return parse_field (ctx, &ptr, end);
1606 static gboolean
1607 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1609 guint32 size = 0;
1610 const char *ptr = NULL, *end;
1612 if (!decode_signature_header (ctx, offset, &size, &ptr))
1613 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1614 end = ptr + size;
1616 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1619 static gboolean
1620 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1622 guint32 size = 0;
1623 unsigned signature = 0;
1624 const char *ptr = NULL, *end;
1626 if (!decode_signature_header (ctx, offset, &size, &ptr))
1627 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1628 end = ptr + size;
1630 if (!safe_read8 (signature, ptr, end))
1631 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1632 --ptr;
1634 if (signature == 0x06)
1635 return parse_field (ctx, &ptr, end);
1637 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1640 static gboolean
1641 is_valid_cattr_blob (VerifyContext *ctx, guint32 offset)
1643 guint32 size = 0;
1644 unsigned prolog = 0;
1645 const char *ptr = NULL, *end;
1647 if (!offset)
1648 return TRUE;
1650 if (!decode_signature_header (ctx, offset, &size, &ptr))
1651 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1652 end = ptr + size;
1654 if (!safe_read16 (prolog, ptr, end))
1655 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1657 if (prolog != 1)
1658 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1660 return TRUE;
1663 static gboolean
1664 is_valid_cattr_type (MonoType *type)
1666 MonoClass *klass;
1668 if (type->type == MONO_TYPE_OBJECT || (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_STRING))
1669 return TRUE;
1671 if (type->type == MONO_TYPE_VALUETYPE) {
1672 klass = mono_class_from_mono_type (type);
1673 return klass && klass->enumtype;
1676 if (type->type == MONO_TYPE_CLASS)
1677 return mono_class_from_mono_type (type) == mono_defaults.systemtype_class;
1679 return FALSE;
1682 static gboolean
1683 is_valid_ser_string_full (VerifyContext *ctx, const char **str_start, guint32 *str_len, const char **_ptr, const char *end)
1685 guint32 size = 0;
1686 const char *ptr = *_ptr;
1688 *str_start = NULL;
1689 *str_len = 0;
1691 if (ptr >= end)
1692 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1694 /*NULL string*/
1695 if (*ptr == (char)0xFF) {
1696 *_ptr = ptr + 1;
1697 return TRUE;
1700 if (!safe_read_cint (size, ptr, end))
1701 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1703 if (ADDP_IS_GREATER_OR_OVF (ptr, size, end))
1704 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string"));
1706 *str_start = ptr;
1707 *str_len = size;
1709 *_ptr = ptr + size;
1710 return TRUE;
1713 static gboolean
1714 is_valid_ser_string (VerifyContext *ctx, const char **_ptr, const char *end)
1716 const char *dummy_str;
1717 guint32 dummy_int;
1718 return is_valid_ser_string_full (ctx, &dummy_str, &dummy_int, _ptr, end);
1721 static MonoClass*
1722 get_enum_by_encoded_name (VerifyContext *ctx, const char **_ptr, const char *end)
1724 MonoType *type;
1725 MonoClass *klass;
1726 const char *str_start = NULL;
1727 const char *ptr = *_ptr;
1728 char *enum_name;
1729 guint32 str_len = 0;
1731 if (!is_valid_ser_string_full (ctx, &str_start, &str_len, &ptr, end))
1732 return NULL;
1734 /*NULL or empty string*/
1735 if (str_start == NULL || str_len == 0) {
1736 ADD_ERROR_NO_RETURN (ctx, g_strdup ("CustomAttribute: Null or empty enum name"));
1737 return NULL;
1740 enum_name = g_memdup (str_start, str_len + 1);
1741 enum_name [str_len] = 0;
1742 type = mono_reflection_type_from_name (enum_name, ctx->image);
1743 if (!type) {
1744 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid enum class %s", enum_name));
1745 g_free (enum_name);
1746 return NULL;
1748 g_free (enum_name);
1750 klass = mono_class_from_mono_type (type);
1751 if (!klass || !klass->enumtype) {
1752 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute:Class %s::%s is not an enum", klass->name_space, klass->name));
1753 return NULL;
1756 *_ptr = ptr;
1757 return klass;
1760 static gboolean
1761 is_valid_fixed_param (VerifyContext *ctx, MonoType *mono_type, const char **_ptr, const char *end)
1763 MonoClass *klass;
1764 const char *ptr = *_ptr;
1765 int elem_size = 0;
1766 guint32 element_count, i;
1767 int type;
1769 klass = mono_type->data.klass;
1770 type = mono_type->type;
1772 handle_enum:
1773 switch (type) {
1774 case MONO_TYPE_BOOLEAN:
1775 case MONO_TYPE_I1:
1776 case MONO_TYPE_U1:
1777 elem_size = 1;
1778 break;
1779 case MONO_TYPE_I2:
1780 case MONO_TYPE_U2:
1781 case MONO_TYPE_CHAR:
1782 elem_size = 2;
1783 break;
1784 case MONO_TYPE_I4:
1785 case MONO_TYPE_U4:
1786 case MONO_TYPE_R4:
1787 elem_size = 4;
1788 break;
1789 case MONO_TYPE_I8:
1790 case MONO_TYPE_U8:
1791 case MONO_TYPE_R8:
1792 elem_size = 8;
1793 break;
1795 case MONO_TYPE_STRING:
1796 *_ptr = ptr;
1797 return is_valid_ser_string (ctx, _ptr, end);
1799 case MONO_TYPE_OBJECT: {
1800 unsigned sub_type = 0;
1801 if (!safe_read8 (sub_type, ptr, end))
1802 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array type"));
1804 if (sub_type >= MONO_TYPE_BOOLEAN && sub_type <= MONO_TYPE_STRING) {
1805 type = sub_type;
1806 goto handle_enum;
1808 if (sub_type == MONO_TYPE_ENUM) {
1809 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1810 if (!klass)
1811 return FALSE;
1813 klass = klass->element_class;
1814 type = klass->byval_arg.type;
1815 goto handle_enum;
1817 if (sub_type == 0x50) { /*Type*/
1818 *_ptr = ptr;
1819 return is_valid_ser_string (ctx, _ptr, end);
1821 if (sub_type == MONO_TYPE_SZARRAY) {
1822 MonoType simple_type = {{0}};
1823 unsigned etype = 0;
1824 if (!safe_read8 (etype, ptr, end))
1825 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1827 if (etype == MONO_TYPE_ENUM) {
1828 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1829 if (!klass)
1830 return FALSE;
1831 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1832 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
1833 klass = mono_class_from_mono_type (&simple_type);
1834 } else
1835 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1837 type = MONO_TYPE_SZARRAY;
1838 goto handle_enum;
1840 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type));
1844 case MONO_TYPE_CLASS:
1845 if (klass != mono_defaults.systemtype_class)
1846 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1847 *_ptr = ptr;
1848 return is_valid_ser_string (ctx, _ptr, end);
1850 case MONO_TYPE_VALUETYPE:
1851 if (!klass || !klass->enumtype)
1852 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass->name_space, klass->name));
1854 klass = klass->element_class;
1855 type = klass->byval_arg.type;
1856 goto handle_enum;
1858 case MONO_TYPE_SZARRAY:
1859 mono_type = &klass->byval_arg;
1860 if (!is_valid_cattr_type (mono_type))
1861 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass->name_space, klass->name));
1862 if (!safe_read32 (element_count, ptr, end))
1863 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1864 if (element_count == 0xFFFFFFFFu) {
1865 *_ptr = ptr;
1866 return TRUE;
1868 for (i = 0; i < element_count; ++i) {
1869 if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
1870 return FALSE;
1872 *_ptr = ptr;
1873 return TRUE;
1874 default:
1875 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
1878 if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
1879 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
1880 *_ptr = ptr + elem_size;
1881 return TRUE;
1884 static gboolean
1885 is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
1887 MonoError error;
1888 unsigned prolog = 0;
1889 const char *end;
1890 MonoMethodSignature *sig;
1891 int args, i;
1892 unsigned num_named;
1894 if (!ctor)
1895 FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
1897 sig = mono_method_signature_checked (ctor, &error);
1898 if (!mono_error_ok (&error)) {
1899 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error)));
1900 mono_error_cleanup (&error);
1901 return FALSE;
1904 if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
1905 FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1907 end = ptr + size;
1909 if (!safe_read16 (prolog, ptr, end))
1910 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1912 if (prolog != 1)
1913 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1915 args = sig->param_count;
1916 for (i = 0; i < args; ++i) {
1917 MonoType *arg_type = sig->params [i];
1918 if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
1919 return FALSE;
1922 if (!safe_read16 (num_named, ptr, end))
1923 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
1925 for (i = 0; i < num_named; ++i) {
1926 MonoType *type, simple_type = {{0}};
1927 unsigned kind;
1929 if (!safe_read8 (kind, ptr, end))
1930 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
1931 if (kind != 0x53 && kind != 0x54)
1932 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
1933 if (!safe_read8 (kind, ptr, end))
1934 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
1936 if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
1937 simple_type.type = kind;
1938 type = &simple_type;
1939 } else if (kind == MONO_TYPE_ENUM) {
1940 MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
1941 if (!klass)
1942 return FALSE;
1943 type = &klass->byval_arg;
1944 } else if (kind == 0x50) {
1945 type = &mono_defaults.systemtype_class->byval_arg;
1946 } else if (kind == 0x51) {
1947 type = &mono_defaults.object_class->byval_arg;
1948 } else if (kind == MONO_TYPE_SZARRAY) {
1949 MonoClass *klass;
1950 unsigned etype = 0;
1951 if (!safe_read8 (etype, ptr, end))
1952 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1954 if (etype == MONO_TYPE_ENUM) {
1955 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1956 if (!klass)
1957 return FALSE;
1958 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1959 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
1960 klass = mono_class_from_mono_type (&simple_type);
1961 } else
1962 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1964 type = &mono_array_class_get (klass, 1)->byval_arg;
1965 } else {
1966 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
1969 if (!is_valid_ser_string (ctx, &ptr, end))
1970 return FALSE;
1972 if (!is_valid_fixed_param (ctx, type, &ptr, end))
1973 return FALSE;
1977 return TRUE;
1980 static gboolean
1981 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1983 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1984 //TODO do proper verification
1985 return blob.size >= 1 && blob.size - 1 >= offset;
1988 static gboolean
1989 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1991 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1992 //TODO do proper verification
1993 return blob.size >= 1 && blob.size - 1 >= offset;
1996 static gboolean
1997 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1999 guint32 size = 0;
2000 unsigned signature = 0;
2001 const char *ptr = NULL, *end;
2003 if (!decode_signature_header (ctx, offset, &size, &ptr))
2004 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
2005 end = ptr + size;
2007 if (!safe_read8 (signature, ptr, end))
2008 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2010 --ptr;
2011 if (signature == 0x07)
2012 return parse_locals_signature (ctx, &ptr, end);
2014 /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
2015 if (signature == 0x06)
2016 return parse_field (ctx, &ptr, end);
2018 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
2021 static gboolean
2022 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
2024 guint32 size = 0;
2025 const char *ptr = NULL, *end;
2027 if (!decode_signature_header (ctx, offset, &size, &ptr))
2028 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
2029 end = ptr + size;
2031 return parse_property_signature (ctx, &ptr, end);
2034 static gboolean
2035 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
2037 guint32 size = 0;
2038 const char *ptr = NULL, *end;
2039 unsigned type = 0;
2041 if (!decode_signature_header (ctx, offset, &size, &ptr))
2042 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
2043 end = ptr + size;
2045 if (!parse_custom_mods (ctx, &ptr, end))
2046 return FALSE;
2048 if (!safe_read8 (type, ptr, end))
2049 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
2051 if (type == MONO_TYPE_BYREF) {
2052 if (!safe_read8 (type, ptr, end))
2053 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
2054 if (type == MONO_TYPE_TYPEDBYREF)
2055 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
2058 if (type == MONO_TYPE_TYPEDBYREF)
2059 return TRUE;
2061 --ptr;
2062 return parse_type (ctx, &ptr, end);
2065 static gboolean
2066 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
2068 guint32 size = 0;
2069 const char *ptr = NULL, *end;
2070 unsigned type = 0;
2071 unsigned count = 0, i;
2073 if (!decode_signature_header (ctx, offset, &size, &ptr))
2074 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
2075 end = ptr + size;
2077 if (!safe_read8 (type, ptr, end))
2078 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
2080 if (type != 0x0A)
2081 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
2083 if (!safe_read_cint (count, ptr, end))
2084 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
2086 if (!count)
2087 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
2089 for (i = 0; i < count; ++i) {
2090 if (!parse_type (ctx, &ptr, end))
2091 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
2093 return TRUE;
2096 static gboolean
2097 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
2099 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2100 guint32 entry_size, bytes;
2102 if (blob.size < offset)
2103 return FALSE;
2105 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2106 return FALSE;
2108 if (entry_size < minsize)
2109 return FALSE;
2111 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
2112 return FALSE;
2113 entry_size += bytes;
2115 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
2118 static gboolean
2119 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
2121 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2122 guint32 size, entry_size, bytes;
2124 if (blob.size < offset)
2125 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
2127 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2128 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
2130 if (type == MONO_TYPE_STRING) {
2131 //String is encoded as: compressed_int:len len *bytes
2132 offset += bytes;
2134 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
2135 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
2137 return TRUE;
2140 switch (type) {
2141 case MONO_TYPE_BOOLEAN:
2142 case MONO_TYPE_I1:
2143 case MONO_TYPE_U1:
2144 size = 1;
2145 break;
2146 case MONO_TYPE_CHAR:
2147 case MONO_TYPE_I2:
2148 case MONO_TYPE_U2:
2149 size = 2;
2150 break;
2151 case MONO_TYPE_I4:
2152 case MONO_TYPE_U4:
2153 case MONO_TYPE_R4:
2154 case MONO_TYPE_CLASS:
2155 size = 4;
2156 break;
2158 case MONO_TYPE_I8:
2159 case MONO_TYPE_U8:
2160 case MONO_TYPE_R8:
2161 size = 8;
2162 break;
2163 default:
2164 g_assert_not_reached ();
2167 if (size != entry_size)
2168 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
2170 offset += bytes;
2172 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
2173 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
2175 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
2176 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
2177 return TRUE;
2180 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
2181 //only 0x01, 0x40 and 0x80 are allowed
2182 #define SECTION_HEADER_INVALID_FLAGS 0x3E
2184 static gboolean
2185 is_valid_method_header (VerifyContext *ctx, guint32 rva)
2187 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
2188 unsigned header = 0;
2189 unsigned fat_header = 0, size = 0, max_stack;
2190 const char *ptr = NULL, *end;
2192 if (offset == INVALID_ADDRESS)
2193 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
2195 ptr = ctx->data + offset;
2196 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
2198 if (!safe_read8 (header, ptr, end))
2199 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
2201 switch (header & 0x3) {
2202 case 0:
2203 case 1:
2204 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
2205 case 2:
2206 header >>= 2;
2207 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
2208 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
2209 return TRUE;
2211 //FAT HEADER
2212 --ptr;
2213 if (!safe_read16 (fat_header, ptr, end))
2214 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
2216 size = (fat_header >> 12) & 0xF;
2217 if (size != 3)
2218 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
2220 if (!safe_read16 (max_stack, ptr, end))
2221 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
2223 if (!safe_read32 (code_size, ptr, end))
2224 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
2226 if (!safe_read32 (local_vars_tok, ptr, end))
2227 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
2229 if (local_vars_tok) {
2230 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
2231 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
2232 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
2233 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
2236 if (fat_header & FAT_HEADER_INVALID_FLAGS)
2237 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
2239 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
2240 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
2242 if (!(fat_header & 0x08))
2243 return TRUE;
2245 ptr += code_size;
2247 do {
2248 unsigned section_header = 0, section_size = 0;
2249 gboolean is_fat;
2251 ptr = dword_align (ptr);
2252 if (!safe_read32 (section_header, ptr, end))
2253 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
2255 if (section_header & SECTION_HEADER_INVALID_FLAGS)
2256 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
2258 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
2259 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
2261 if (section_size < 4)
2262 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
2264 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
2265 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
2267 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
2268 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
2270 LAMEIMPL: MS emits section_size without accounting for header size.
2271 Mono does as the spec says. section_size is header + section
2272 MS's peverify happily accepts both.
2274 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
2275 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)));
2277 /* only verify the class token is verified as the rest is done by the IL verifier*/
2278 for (i = 0; i < clauses; ++i) {
2279 unsigned flags = *(unsigned char*)ptr;
2280 unsigned class_token = 0;
2281 ptr += (is_fat ? 20 : 8);
2282 if (!safe_read32 (class_token, ptr, end))
2283 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
2284 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
2285 guint table = mono_metadata_token_table (class_token);
2286 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
2287 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
2288 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
2289 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
2294 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
2295 break;
2296 } while (1);
2297 return TRUE;
2300 static void
2301 verify_module_table (VerifyContext *ctx)
2303 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
2304 guint32 data [MONO_MODULE_SIZE];
2306 if (table->rows != 1)
2307 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
2309 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
2311 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
2312 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
2314 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
2315 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
2317 if (data [MONO_MODULE_ENC] != 0)
2318 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
2320 if (data [MONO_MODULE_ENCBASE] != 0)
2321 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
2324 static void
2325 verify_typeref_table (VerifyContext *ctx)
2327 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2328 guint32 data [MONO_TYPEREF_SIZE];
2329 int i;
2331 for (i = 0; i < table->rows; ++i) {
2332 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
2333 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
2334 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
2336 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
2337 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
2339 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
2340 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
2342 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2343 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
2347 /*bits 9,11,14,15,19,21,24-31 */
2348 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2349 static void
2350 verify_typedef_table (VerifyContext *ctx)
2352 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2353 guint32 data [MONO_TYPEDEF_SIZE];
2354 guint32 fieldlist = 1, methodlist = 1, visibility;
2355 int i;
2357 if (table->rows == 0)
2358 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2360 for (i = 0; i < table->rows; ++i) {
2361 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2362 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2363 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2365 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2366 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2368 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2369 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2371 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2372 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2374 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2375 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2377 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2378 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2380 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2381 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2383 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2384 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2386 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2387 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2388 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2389 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2391 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2392 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2394 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2395 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2397 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2398 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));
2400 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2401 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2403 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2404 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2406 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2407 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));
2409 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2410 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2414 static void
2415 verify_typedef_table_full (VerifyContext *ctx)
2417 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2418 guint32 data [MONO_TYPEDEF_SIZE];
2419 int i;
2421 if (table->rows == 0)
2422 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2424 for (i = 0; i < table->rows; ++i) {
2425 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2427 if (i == 0) {
2428 /*XXX it's ok if <module> extends object, or anything at all, actually. */
2429 /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
2430 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2432 continue;
2435 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2436 if (data [MONO_TYPEDEF_EXTENDS])
2437 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2438 } else {
2439 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2440 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2442 if (is_sys_obj) {
2443 if (has_parent)
2444 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2445 } else {
2446 if (!has_parent) {
2447 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2454 /*bits 3,11,14 */
2455 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2456 static void
2457 verify_field_table (VerifyContext *ctx)
2459 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2460 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2461 int i;
2463 module_field_list = (guint32)-1;
2464 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2465 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2466 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2469 for (i = 0; i < table->rows; ++i) {
2470 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2471 flags = data [MONO_FIELD_FLAGS];
2473 if (flags & INVALID_FIELD_FLAG_BITS)
2474 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2476 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2477 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2479 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2480 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2482 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2483 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2485 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2486 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2488 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2489 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2490 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2492 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2493 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2494 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2496 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2497 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2498 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2500 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2501 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2502 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2504 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2505 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2507 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2508 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2510 //TODO verify contant flag
2512 if (i + 1 < module_field_list) {
2513 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2514 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2515 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2516 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2517 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2522 static void
2523 verify_field_table_full (VerifyContext *ctx)
2525 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2526 guint32 data [MONO_FIELD_SIZE];
2527 int i;
2529 for (i = 0; i < table->rows; ++i) {
2530 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2532 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2533 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2537 /*bits 8,9,10,11,13,14,15*/
2538 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2539 static void
2540 verify_method_table (VerifyContext *ctx)
2542 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2543 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2544 guint32 paramlist = 1;
2545 gboolean is_ctor, is_cctor;
2546 const char *name;
2547 int i;
2549 module_method_list = (guint32)-1;
2550 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2551 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2552 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2555 for (i = 0; i < table->rows; ++i) {
2556 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2557 rva = data [MONO_METHOD_RVA];
2558 implflags = data [MONO_METHOD_IMPLFLAGS];
2559 flags = data [MONO_METHOD_FLAGS];
2560 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2561 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2564 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2565 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2567 if (access == 0x7)
2568 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2570 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2571 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2573 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2574 is_ctor = !strcmp (".ctor", name);
2575 is_cctor = !strcmp (".cctor", name);
2577 if ((is_ctor || is_cctor) &&
2578 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2579 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2581 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2582 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2584 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2585 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2586 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2587 if (flags & METHOD_ATTRIBUTE_FINAL)
2588 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2589 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2590 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2593 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2594 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2596 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2597 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2599 //XXX no checks against cas stuff 10,11,12,13)
2601 //TODO check iface with .ctor (15,16)
2603 if (i + 1 < module_method_list) {
2604 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2605 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2606 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2607 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2608 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2609 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2612 //TODO check valuetype for synchronized
2614 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2615 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2617 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2618 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2619 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2620 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2621 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2624 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2625 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2626 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2628 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2629 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2631 //TODO check signature contents
2633 if (rva) {
2634 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2635 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2636 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2637 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2638 } else {
2639 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2640 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2643 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2644 if (rva)
2645 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2646 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2647 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2649 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2650 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2652 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2653 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2655 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2656 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2658 if (data [MONO_METHOD_PARAMLIST] == 0)
2659 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2661 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2662 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));
2664 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2665 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2667 paramlist = data [MONO_METHOD_PARAMLIST];
2672 static void
2673 verify_method_table_full (VerifyContext *ctx)
2675 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2676 guint32 data [MONO_METHOD_SIZE], rva;
2677 int i;
2679 for (i = 0; i < table->rows; ++i) {
2680 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2681 rva = data [MONO_METHOD_RVA];
2683 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2684 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2686 if (rva && !is_valid_method_header (ctx, rva))
2687 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2691 static guint32
2692 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2694 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2695 guint32 row = *current_method;
2696 guint32 paramlist, tmp;
2699 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2700 while (row < table->rows) {
2701 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2702 if (tmp > paramlist) {
2703 *current_method = row;
2704 return tmp - paramlist;
2706 ++row;
2709 /*no more methods, all params apply to the last one*/
2710 *current_method = table->rows;
2711 return (guint32)-1;
2715 #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))
2716 static void
2717 verify_param_table (VerifyContext *ctx)
2719 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2720 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2721 gboolean first_param = TRUE;
2722 int i;
2724 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2725 if (table->rows > 0)
2726 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2727 return;
2730 remaining_params = get_next_param_count (ctx, &current_method);
2732 for (i = 0; i < table->rows; ++i) {
2733 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2734 flags = data [MONO_PARAM_FLAGS];
2736 if (flags & INVALID_PARAM_FLAGS_BITS)
2737 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2739 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2740 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2741 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2742 } else {
2743 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2744 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2747 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)
2748 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2750 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2751 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2753 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2754 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2756 first_param = FALSE;
2757 sequence = data [MONO_PARAM_SEQUENCE];
2758 if (--remaining_params == 0) {
2759 remaining_params = get_next_param_count (ctx, &current_method);
2760 first_param = TRUE;
2765 static void
2766 verify_interfaceimpl_table (VerifyContext *ctx)
2768 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2769 guint32 data [MONO_INTERFACEIMPL_SIZE];
2770 int i;
2772 for (i = 0; i < table->rows; ++i) {
2773 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2774 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2775 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2777 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2778 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2780 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2781 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2785 static void
2786 verify_memberref_table (VerifyContext *ctx)
2788 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2789 guint32 data [MONO_MEMBERREF_SIZE];
2790 int i;
2792 for (i = 0; i < table->rows; ++i) {
2793 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2795 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2796 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2798 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2799 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2801 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2802 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2804 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2805 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2810 static void
2811 verify_memberref_table_full (VerifyContext *ctx)
2813 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2814 guint32 data [MONO_MEMBERREF_SIZE];
2815 int i;
2817 for (i = 0; i < table->rows; ++i) {
2818 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2820 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2821 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2825 static void
2826 verify_constant_table (VerifyContext *ctx)
2828 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2829 guint32 data [MONO_CONSTANT_SIZE], type;
2830 int i;
2832 for (i = 0; i < table->rows; ++i) {
2833 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2834 type = data [MONO_CONSTANT_TYPE];
2836 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2837 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2839 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2840 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2842 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2843 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2845 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2846 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2850 static void
2851 verify_cattr_table (VerifyContext *ctx)
2853 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2854 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2855 int i;
2857 for (i = 0; i < table->rows; ++i) {
2858 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2860 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2861 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2863 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2864 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2866 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2867 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2871 static void
2872 verify_cattr_table_full (VerifyContext *ctx)
2874 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2875 MonoMethod *ctor;
2876 const char *ptr;
2877 guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2878 int i;
2880 for (i = 0; i < table->rows; ++i) {
2881 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2883 if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2884 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2886 mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2887 switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2888 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2889 mtoken |= MONO_TOKEN_METHOD_DEF;
2890 break;
2891 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2892 mtoken |= MONO_TOKEN_MEMBER_REF;
2893 break;
2894 default:
2895 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2898 ctor = mono_get_method (ctx->image, mtoken, NULL);
2900 /*This can't fail since this is checked in is_valid_cattr_blob*/
2901 g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
2903 if (!is_valid_cattr_content (ctx, ctor, ptr, size))
2904 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2908 static void
2909 verify_field_marshal_table (VerifyContext *ctx)
2911 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2912 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2913 int i;
2915 for (i = 0; i < table->rows; ++i) {
2916 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2918 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2919 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2921 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2922 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2924 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2925 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2927 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2928 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2932 static void
2933 verify_field_marshal_table_full (VerifyContext *ctx)
2935 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2936 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2937 int i;
2939 for (i = 0; i < table->rows; ++i) {
2940 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2942 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2943 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2947 static void
2948 verify_decl_security_table (VerifyContext *ctx)
2950 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2951 guint32 data [MONO_DECL_SECURITY_SIZE];
2952 int i;
2954 for (i = 0; i < table->rows; ++i) {
2955 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2957 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2958 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2960 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2961 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2963 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2964 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2968 static void
2969 verify_decl_security_table_full (VerifyContext *ctx)
2971 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2972 guint32 data [MONO_DECL_SECURITY_SIZE];
2973 int i;
2975 for (i = 0; i < table->rows; ++i) {
2976 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2978 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2979 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2983 static void
2984 verify_class_layout_table (VerifyContext *ctx)
2986 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2987 guint32 data [MONO_CLASS_LAYOUT_SIZE];
2988 int i;
2990 for (i = 0; i < table->rows; ++i) {
2991 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2993 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2994 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2996 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2997 case 0:
2998 case 1:
2999 case 2:
3000 case 4:
3001 case 8:
3002 case 16:
3003 case 32:
3004 case 64:
3005 case 128:
3006 break;
3007 default:
3008 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3013 static void
3014 verify_field_layout_table (VerifyContext *ctx)
3016 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3017 guint32 data [MONO_FIELD_LAYOUT_SIZE];
3018 int i;
3020 for (i = 0; i < table->rows; ++i) {
3021 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
3023 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3024 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
3028 static void
3029 verify_standalonesig_table (VerifyContext *ctx)
3031 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3032 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3033 int i;
3035 for (i = 0; i < table->rows; ++i) {
3036 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3038 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
3039 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3043 static void
3044 verify_standalonesig_table_full (VerifyContext *ctx)
3046 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3047 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3048 int i;
3050 for (i = 0; i < table->rows; ++i) {
3051 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3053 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
3054 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3058 static void
3059 verify_eventmap_table (VerifyContext *ctx)
3061 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3062 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3063 int i;
3065 for (i = 0; i < table->rows; ++i) {
3066 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
3068 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3069 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
3071 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
3072 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
3074 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
3078 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3079 static void
3080 verify_event_table (VerifyContext *ctx)
3082 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3083 guint32 data [MONO_EVENT_SIZE];
3084 int i;
3086 for (i = 0; i < table->rows; ++i) {
3087 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3089 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
3090 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
3092 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
3093 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
3095 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
3096 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
3100 static void
3101 verify_event_table_full (VerifyContext *ctx)
3103 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3104 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
3105 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
3106 gboolean found_add, found_remove;
3107 int i, idx;
3109 for (i = 0; i < table->rows; ++i) {
3110 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3112 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
3113 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
3114 if (idx == -1)
3115 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
3117 //first we move to the first row for this event
3118 while (idx > 0) {
3119 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3120 break;
3121 --idx;
3123 //now move forward looking for AddOn and RemoveOn rows
3124 found_add = found_remove = FALSE;
3125 while (idx < sema_table->rows) {
3126 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
3127 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
3128 break;
3129 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3130 found_add = TRUE;
3131 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3132 found_remove = TRUE;
3133 if (found_add && found_remove)
3134 break;
3135 ++idx;
3138 if (!found_add)
3139 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3140 if (!found_remove)
3141 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3145 static void
3146 verify_propertymap_table (VerifyContext *ctx)
3148 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3149 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3150 int i;
3152 for (i = 0; i < table->rows; ++i) {
3153 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
3155 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3156 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
3158 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
3159 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
3161 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
3165 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3166 static void
3167 verify_property_table (VerifyContext *ctx)
3169 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3170 guint32 data [MONO_PROPERTY_SIZE];
3171 int i;
3173 for (i = 0; i < table->rows; ++i) {
3174 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
3176 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
3177 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
3179 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
3180 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
3182 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
3183 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
3185 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
3186 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
3187 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
3192 static void
3193 verify_methodimpl_table (VerifyContext *ctx)
3195 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3196 guint32 data [MONO_METHODIMPL_SIZE];
3197 int i;
3199 for (i = 0; i < table->rows; ++i) {
3200 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3202 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3203 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3205 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3206 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3208 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3209 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3211 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3212 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3214 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3215 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3219 static void
3220 verify_moduleref_table (VerifyContext *ctx)
3222 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3223 guint32 data [MONO_MODULEREF_SIZE];
3224 int i;
3226 for (i = 0; i < table->rows; ++i) {
3227 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
3229 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
3230 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3234 static void
3235 verify_typespec_table (VerifyContext *ctx)
3237 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3238 guint32 data [MONO_TYPESPEC_SIZE];
3239 int i;
3241 for (i = 0; i < table->rows; ++i) {
3242 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3244 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
3245 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3249 static void
3250 verify_typespec_table_full (VerifyContext *ctx)
3252 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3253 guint32 data [MONO_TYPESPEC_SIZE];
3254 int i;
3256 for (i = 0; i < table->rows; ++i) {
3257 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3258 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
3259 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
3260 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3262 ctx->token = 0;
3265 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 12) | (1 << 13))
3266 static void
3267 verify_implmap_table (VerifyContext *ctx)
3269 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3270 guint32 data [MONO_IMPLMAP_SIZE], cconv;
3271 int i;
3273 for (i = 0; i < table->rows; ++i) {
3274 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
3276 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
3277 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
3279 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
3280 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
3281 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
3283 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3284 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
3286 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
3287 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
3289 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3290 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
3292 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
3293 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
3295 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
3296 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
3300 static void
3301 verify_fieldrva_table (VerifyContext *ctx)
3303 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3304 guint32 data [MONO_FIELD_RVA_SIZE];
3305 int i;
3307 for (i = 0; i < table->rows; ++i) {
3308 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
3310 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
3311 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
3313 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3314 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
3318 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
3319 static void
3320 verify_assembly_table (VerifyContext *ctx)
3322 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3323 guint32 data [MONO_ASSEMBLY_SIZE], hash;
3324 int i;
3326 if (table->rows > 1)
3327 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
3329 for (i = 0; i < table->rows; ++i) {
3330 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
3332 hash = data [MONO_ASSEMBLY_HASH_ALG];
3333 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
3334 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
3336 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
3337 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3339 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
3340 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3342 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3343 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3345 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3346 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3350 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
3351 static void
3352 verify_assemblyref_table (VerifyContext *ctx)
3354 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3355 guint32 data [MONO_ASSEMBLYREF_SIZE];
3356 int i;
3358 for (i = 0; i < table->rows; ++i) {
3359 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3361 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3362 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3364 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3365 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3367 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3368 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3370 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3371 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3373 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3374 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3378 #define INVALID_FILE_FLAGS_BITS ~(1)
3379 static void
3380 verify_file_table (VerifyContext *ctx)
3382 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3383 guint32 data [MONO_FILE_SIZE];
3384 int i;
3386 for (i = 0; i < table->rows; ++i) {
3387 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3389 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3390 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3392 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3393 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3395 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3396 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3400 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3401 static void
3402 verify_exportedtype_table (VerifyContext *ctx)
3404 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3405 guint32 data [MONO_EXP_TYPE_SIZE];
3406 int i;
3408 for (i = 0; i < table->rows; ++i) {
3409 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3411 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3412 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3414 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3415 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3417 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3418 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3420 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3421 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3423 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3424 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3426 /*nested type can't have a namespace*/
3427 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3428 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3432 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3433 static void
3434 verify_manifest_resource_table (VerifyContext *ctx)
3436 MonoCLIImageInfo *iinfo = ctx->image->image_info;
3437 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3438 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3439 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3440 int i;
3442 resources_size = ch->ch_resources.size;
3444 for (i = 0; i < table->rows; ++i) {
3445 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3447 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3448 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3450 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3451 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3453 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3454 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3456 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3457 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3459 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3460 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3462 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3463 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])));
3465 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3466 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3468 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3469 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3473 static void
3474 verify_nested_class_table (VerifyContext *ctx)
3476 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3477 guint32 data [MONO_NESTED_CLASS_SIZE];
3478 int i;
3480 for (i = 0; i < table->rows; ++i) {
3481 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3483 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3484 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3485 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3486 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3487 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3488 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3492 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3493 static void
3494 verify_generic_param_table (VerifyContext *ctx)
3496 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3497 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3498 int i, param_number = 0;
3500 for (i = 0; i < table->rows; ++i) {
3501 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3503 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3504 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3506 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3507 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3509 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3510 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3512 token = data [MONO_GENERICPARAM_OWNER];
3514 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3515 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3517 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3518 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3520 if (token != last_token) {
3521 param_number = 0;
3522 last_token = token;
3525 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3526 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));
3528 ++param_number;
3532 static void
3533 verify_method_spec_table (VerifyContext *ctx)
3535 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3536 guint32 data [MONO_METHODSPEC_SIZE];
3537 int i;
3539 for (i = 0; i < table->rows; ++i) {
3540 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3542 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3543 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3545 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3546 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3548 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3549 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3553 static void
3554 verify_method_spec_table_full (VerifyContext *ctx)
3556 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3557 guint32 data [MONO_METHODSPEC_SIZE];
3558 int i;
3560 for (i = 0; i < table->rows; ++i) {
3561 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3563 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3564 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3568 static void
3569 verify_generic_param_constraint_table (VerifyContext *ctx)
3571 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3572 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3573 int i;
3575 for (i = 0; i < table->rows; ++i) {
3576 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3578 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3579 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3581 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3582 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3584 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3585 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3590 typedef struct {
3591 const char *name;
3592 const char *name_space;
3593 guint32 resolution_scope;
3594 } TypeDefUniqueId;
3596 static guint
3597 typedef_hash (gconstpointer _key)
3599 const TypeDefUniqueId *key = _key;
3600 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3603 static gboolean
3604 typedef_equals (gconstpointer _a, gconstpointer _b)
3606 const TypeDefUniqueId *a = _a;
3607 const TypeDefUniqueId *b = _b;
3608 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3611 static void
3612 verify_typedef_table_global_constraints (VerifyContext *ctx)
3614 int i;
3615 guint32 data [MONO_TYPEDEF_SIZE];
3616 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3617 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3618 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3619 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3621 for (i = 0; i < table->rows; ++i) {
3622 guint visibility;
3623 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3624 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3626 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3627 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3628 type->resolution_scope = 0;
3630 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3631 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3632 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3633 g_assert (res >= 0);
3635 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3636 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3639 if (g_hash_table_lookup (unique_types, type)) {
3640 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));
3641 g_hash_table_destroy (unique_types);
3642 g_free (type);
3643 return;
3645 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3648 g_hash_table_destroy (unique_types);
3651 static void
3652 verify_typeref_table_global_constraints (VerifyContext *ctx)
3654 int i;
3655 guint32 data [MONO_TYPEREF_SIZE];
3656 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3657 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3659 for (i = 0; i < table->rows; ++i) {
3660 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3661 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3663 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3664 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3665 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3667 if (g_hash_table_lookup (unique_types, type)) {
3668 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));
3669 g_hash_table_destroy (unique_types);
3670 g_free (type);
3671 return;
3673 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3676 g_hash_table_destroy (unique_types);
3679 static void
3680 verify_tables_data_global_constraints (VerifyContext *ctx)
3682 verify_typedef_table_global_constraints (ctx);
3685 static void
3686 verify_tables_data_global_constraints_full (VerifyContext *ctx)
3688 verify_typeref_table_global_constraints (ctx);
3691 static void
3692 verify_tables_data (VerifyContext *ctx)
3694 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3695 guint32 size = 0, tables_offset;
3696 int i;
3698 for (i = 0; i < 0x2D; ++i) {
3699 MonoTableInfo *table = &ctx->image->tables [i];
3700 guint32 tmp_size;
3701 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3702 if (tmp_size < size) {
3703 size = 0;
3704 break;
3706 size = tmp_size;
3709 if (size == 0)
3710 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3712 tables_offset = ctx->image->tables_base - ctx->data;
3713 if (!bounds_check_offset (&tables_area, tables_offset, size))
3714 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)));
3716 verify_module_table (ctx);
3717 CHECK_ERROR ();
3718 verify_typeref_table (ctx);
3719 CHECK_ERROR ();
3720 verify_typedef_table (ctx);
3721 CHECK_ERROR ();
3722 verify_field_table (ctx);
3723 CHECK_ERROR ();
3724 verify_method_table (ctx);
3725 CHECK_ERROR ();
3726 verify_param_table (ctx);
3727 CHECK_ERROR ();
3728 verify_interfaceimpl_table (ctx);
3729 CHECK_ERROR ();
3730 verify_memberref_table (ctx);
3731 CHECK_ERROR ();
3732 verify_constant_table (ctx);
3733 CHECK_ERROR ();
3734 verify_cattr_table (ctx);
3735 CHECK_ERROR ();
3736 verify_field_marshal_table (ctx);
3737 CHECK_ERROR ();
3738 verify_decl_security_table (ctx);
3739 CHECK_ERROR ();
3740 verify_class_layout_table (ctx);
3741 CHECK_ERROR ();
3742 verify_field_layout_table (ctx);
3743 CHECK_ERROR ();
3744 verify_standalonesig_table (ctx);
3745 CHECK_ERROR ();
3746 verify_eventmap_table (ctx);
3747 CHECK_ERROR ();
3748 verify_event_table (ctx);
3749 CHECK_ERROR ();
3750 verify_propertymap_table (ctx);
3751 CHECK_ERROR ();
3752 verify_property_table (ctx);
3753 CHECK_ERROR ();
3754 verify_methodimpl_table (ctx);
3755 CHECK_ERROR ();
3756 verify_moduleref_table (ctx);
3757 CHECK_ERROR ();
3758 verify_typespec_table (ctx);
3759 CHECK_ERROR ();
3760 verify_implmap_table (ctx);
3761 CHECK_ERROR ();
3762 verify_fieldrva_table (ctx);
3763 CHECK_ERROR ();
3764 verify_assembly_table (ctx);
3765 CHECK_ERROR ();
3766 verify_assemblyref_table (ctx);
3767 CHECK_ERROR ();
3768 verify_file_table (ctx);
3769 CHECK_ERROR ();
3770 verify_exportedtype_table (ctx);
3771 CHECK_ERROR ();
3772 verify_manifest_resource_table (ctx);
3773 CHECK_ERROR ();
3774 verify_nested_class_table (ctx);
3775 CHECK_ERROR ();
3776 verify_generic_param_table (ctx);
3777 CHECK_ERROR ();
3778 verify_method_spec_table (ctx);
3779 CHECK_ERROR ();
3780 verify_generic_param_constraint_table (ctx);
3781 CHECK_ERROR ();
3782 verify_tables_data_global_constraints (ctx);
3785 static void
3786 init_verify_context (VerifyContext *ctx, MonoImage *image, gboolean report_error)
3788 memset (ctx, 0, sizeof (VerifyContext));
3789 ctx->image = image;
3790 ctx->report_error = report_error;
3791 ctx->report_warning = FALSE; //export this setting in the API
3792 ctx->valid = 1;
3793 ctx->size = image->raw_data_len;
3794 ctx->data = image->raw_data;
3797 static gboolean
3798 cleanup_context (VerifyContext *ctx, GSList **error_list)
3800 g_free (ctx->sections);
3801 if (error_list)
3802 *error_list = ctx->errors;
3803 else
3804 mono_free_verify_list (ctx->errors);
3805 return ctx->valid;
3808 static gboolean
3809 cleanup_context_checked (VerifyContext *ctx, MonoError *error)
3811 g_free (ctx->sections);
3812 if (ctx->errors) {
3813 MonoVerifyInfo *info = ctx->errors->data;
3814 mono_error_set_bad_image (error, ctx->image, "%s", info->message);
3815 mono_free_verify_list (ctx->errors);
3817 return ctx->valid;
3820 gboolean
3821 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3823 VerifyContext ctx;
3825 if (!mono_verifier_is_enabled_for_image (image))
3826 return TRUE;
3828 init_verify_context (&ctx, image, error_list != NULL);
3829 ctx.stage = STAGE_PE;
3831 verify_msdos_header (&ctx);
3832 CHECK_STATE();
3833 verify_pe_header (&ctx);
3834 CHECK_STATE();
3835 verify_pe_optional_header (&ctx);
3836 CHECK_STATE();
3837 load_section_table (&ctx);
3838 CHECK_STATE();
3839 load_data_directories (&ctx);
3840 CHECK_STATE();
3841 verify_import_table (&ctx);
3842 CHECK_STATE();
3843 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3844 verify_resources_table (&ctx);
3846 cleanup:
3847 return cleanup_context (&ctx, error_list);
3850 gboolean
3851 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3853 VerifyContext ctx;
3855 if (!mono_verifier_is_enabled_for_image (image))
3856 return TRUE;
3858 init_verify_context (&ctx, image, error_list != NULL);
3859 ctx.stage = STAGE_CLI;
3861 verify_cli_header (&ctx);
3862 CHECK_STATE();
3863 verify_metadata_header (&ctx);
3864 CHECK_STATE();
3865 verify_tables_schema (&ctx);
3867 cleanup:
3868 return cleanup_context (&ctx, error_list);
3873 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3874 * Other verification checks are meant to be done lazily by the runtime. Those include:
3875 * blob items (signatures, method headers, custom attributes, etc)
3876 * type semantics related
3877 * vtable related
3878 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3880 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3881 * operation still need more checking.
3883 gboolean
3884 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3886 VerifyContext ctx;
3888 if (!mono_verifier_is_enabled_for_image (image))
3889 return TRUE;
3891 init_verify_context (&ctx, image, error_list != NULL);
3892 ctx.stage = STAGE_TABLES;
3894 verify_tables_data (&ctx);
3896 return cleanup_context (&ctx, error_list);
3901 * Verifies all other constraints.
3903 gboolean
3904 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3906 VerifyContext ctx;
3908 if (!mono_verifier_is_enabled_for_image (image))
3909 return TRUE;
3911 init_verify_context (&ctx, image, error_list != NULL);
3912 ctx.stage = STAGE_TABLES;
3914 verify_typedef_table_full (&ctx);
3915 CHECK_STATE ();
3916 verify_field_table_full (&ctx);
3917 CHECK_STATE ();
3918 verify_method_table_full (&ctx);
3919 CHECK_STATE ();
3920 verify_memberref_table_full (&ctx);
3921 CHECK_STATE ();
3922 verify_cattr_table_full (&ctx);
3923 CHECK_STATE ();
3924 verify_field_marshal_table_full (&ctx);
3925 CHECK_STATE ();
3926 verify_decl_security_table_full (&ctx);
3927 CHECK_STATE ();
3928 verify_standalonesig_table_full (&ctx);
3929 CHECK_STATE ();
3930 verify_event_table_full (&ctx);
3931 CHECK_STATE ();
3932 verify_typespec_table_full (&ctx);
3933 CHECK_STATE ();
3934 verify_method_spec_table_full (&ctx);
3935 CHECK_STATE ();
3936 verify_tables_data_global_constraints_full (&ctx);
3938 cleanup:
3939 return cleanup_context (&ctx, error_list);
3942 gboolean
3943 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3945 VerifyContext ctx;
3947 if (!mono_verifier_is_enabled_for_image (image))
3948 return TRUE;
3950 init_verify_context (&ctx, image, error_list != NULL);
3951 ctx.stage = STAGE_TABLES;
3953 is_valid_field_signature (&ctx, offset);
3954 return cleanup_context (&ctx, error_list);
3957 gboolean
3958 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3960 VerifyContext ctx;
3962 if (!mono_verifier_is_enabled_for_image (image))
3963 return TRUE;
3965 init_verify_context (&ctx, image, error_list != NULL);
3966 ctx.stage = STAGE_TABLES;
3968 is_valid_method_header (&ctx, offset);
3969 return cleanup_context (&ctx, error_list);
3972 gboolean
3973 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
3975 VerifyContext ctx;
3977 mono_error_init (error);
3979 if (!mono_verifier_is_enabled_for_image (image))
3980 return TRUE;
3982 init_verify_context (&ctx, image, TRUE);
3983 ctx.stage = STAGE_TABLES;
3985 is_valid_method_signature (&ctx, offset);
3986 /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
3987 return cleanup_context_checked (&ctx, error);
3990 gboolean
3991 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3993 VerifyContext ctx;
3995 if (!mono_verifier_is_enabled_for_image (image))
3996 return TRUE;
3998 init_verify_context (&ctx, image, error_list != NULL);
3999 ctx.stage = STAGE_TABLES;
4001 is_valid_method_or_field_signature (&ctx, offset);
4002 return cleanup_context (&ctx, error_list);
4005 gboolean
4006 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4008 VerifyContext ctx;
4010 if (!mono_verifier_is_enabled_for_image (image))
4011 return TRUE;
4013 init_verify_context (&ctx, image, error_list != NULL);
4014 ctx.stage = STAGE_TABLES;
4016 is_valid_standalonesig_blob (&ctx, offset);
4017 return cleanup_context (&ctx, error_list);
4020 gboolean
4021 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, 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 != NULL);
4029 ctx.stage = STAGE_TABLES;
4030 ctx.token = token;
4032 is_valid_typespec_blob (&ctx, offset);
4033 return cleanup_context (&ctx, error_list);
4036 gboolean
4037 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4039 VerifyContext ctx;
4041 if (!mono_verifier_is_enabled_for_image (image))
4042 return TRUE;
4044 init_verify_context (&ctx, image, error_list != NULL);
4045 ctx.stage = STAGE_TABLES;
4047 is_valid_methodspec_blob (&ctx, offset);
4048 return cleanup_context (&ctx, error_list);
4051 static void
4052 verify_user_string (VerifyContext *ctx, guint32 offset)
4054 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
4055 guint32 entry_size, bytes;
4057 if (heap_us.size < offset)
4058 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
4060 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
4061 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
4063 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
4064 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
4066 entry_size += bytes;
4068 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
4069 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
4072 gboolean
4073 mono_verifier_verify_string_signature (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 != NULL);
4081 ctx.stage = STAGE_TABLES;
4083 verify_user_string (&ctx, offset);
4085 return cleanup_context (&ctx, error_list);
4088 gboolean
4089 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, 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 != NULL);
4097 ctx.stage = STAGE_TABLES;
4099 is_valid_cattr_blob (&ctx, offset);
4101 return cleanup_context (&ctx, error_list);
4104 gboolean
4105 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4107 VerifyContext ctx;
4109 if (!mono_verifier_is_enabled_for_image (image))
4110 return TRUE;
4112 init_verify_context (&ctx, image, error_list != NULL);
4113 ctx.stage = STAGE_TABLES;
4115 is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
4117 return cleanup_context (&ctx, error_list);
4120 gboolean
4121 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4123 MonoMethodSignature *original_sig;
4124 if (!mono_verifier_is_enabled_for_image (image))
4125 return TRUE;
4127 original_sig = mono_method_signature (method);
4128 if (original_sig->call_convention == MONO_CALL_VARARG) {
4129 if (original_sig->hasthis != signature->hasthis)
4130 return FALSE;
4131 if (original_sig->call_convention != signature->call_convention)
4132 return FALSE;
4133 if (original_sig->explicit_this != signature->explicit_this)
4134 return FALSE;
4135 if (original_sig->call_convention != signature->call_convention)
4136 return FALSE;
4137 if (original_sig->pinvoke != signature->pinvoke)
4138 return FALSE;
4139 if (original_sig->sentinelpos != signature->sentinelpos)
4140 return FALSE;
4141 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4142 return FALSE;
4145 return TRUE;
4148 #else
4149 gboolean
4150 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4152 return TRUE;
4155 gboolean
4156 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
4158 return TRUE;
4161 gboolean
4162 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
4164 return TRUE;
4167 gboolean
4168 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4170 return TRUE;
4173 gboolean
4174 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4176 return TRUE;
4179 gboolean
4180 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4182 return TRUE;
4185 gboolean
4186 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4188 mono_error_init (error);
4189 return TRUE;
4192 gboolean
4193 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
4195 return TRUE;
4198 gboolean
4199 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4201 return TRUE;
4204 gboolean
4205 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4207 return TRUE;
4210 gboolean
4211 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4213 return TRUE;
4216 gboolean
4217 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4219 return TRUE;
4222 gboolean
4223 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4225 return TRUE;
4228 gboolean
4229 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4231 return TRUE;
4234 gboolean
4235 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4237 return TRUE;
4241 #endif /* DISABLE_VERIFIER */