61a00c69ee7c613fe6ded94b1c2f5974ae2c5e18
[mono.git] / mono / metadata / metadata-verify.c
1 /*
2  * metadata-verify.c: Metadata verfication support
3  *
4  * Author:
5  *      Mono Project (http://www.mono-project.com)
6  *
7  * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
8  */
9 #include <mono/metadata/object-internals.h>
10 #include <mono/metadata/verify.h>
11 #include <mono/metadata/verify-internals.h>
12 #include <mono/metadata/opcodes.h>
13 #include <mono/metadata/tabledefs.h>
14 #include <mono/metadata/reflection.h>
15 #include <mono/metadata/debug-helpers.h>
16 #include <mono/metadata/mono-endian.h>
17 #include <mono/metadata/metadata.h>
18 #include <mono/metadata/metadata-internals.h>
19 #include <mono/metadata/class-internals.h>
20 #include <mono/metadata/tokentype.h>
21 #include <mono/metadata/security-manager.h>
22 #include <mono/metadata/security-core-clr.h>
23 #include <mono/metadata/cil-coff.h>
24 #include <mono/metadata/attrdefs.h>
25 #include <mono/utils/strenc.h>
26 #include <string.h>
27 //#include <signal.h>
28 #include <ctype.h>
29
30 #ifndef DISABLE_VERIFIER
31 /*
32  TODO add fail fast mode
33  TODO add PE32+ support
34  TODO verify the entry point RVA and content.
35  TODO load_section_table and load_data_directories must take PE32+ into account
36  TODO add section relocation support
37  TODO verify the relocation table, since we really don't use, no need so far.
38  TODO do full PECOFF resources verification 
39  TODO verify in the CLI header entry point and resources
40  TODO implement null token typeref validation  
41  TODO verify table wide invariants for typedef (sorting and uniqueness)
42  TODO implement proper authenticode data directory validation
43  TODO verify properties that require multiple tables to be valid 
44  FIXME use subtraction based bounds checking to avoid overflows
45  FIXME get rid of metadata_streams and other fields from VerifyContext
46 */
47
48 #ifdef MONO_VERIFIER_DEBUG
49 #define VERIFIER_DEBUG(code) do { code; } while (0)
50 #else
51 #define VERIFIER_DEBUG(code)
52 #endif
53
54 #define INVALID_OFFSET ((guint32)-1)
55 #define INVALID_ADDRESS 0xffffffff
56
57 enum {
58         STAGE_PE,
59         STAGE_CLI,
60         STAGE_TABLES
61 };
62
63 enum {
64         IMPORT_TABLE_IDX = 1, 
65         RESOURCE_TABLE_IDX = 2,
66         CERTIFICATE_TABLE_IDX = 4,
67         RELOCATION_TABLE_IDX = 5,
68         IAT_IDX = 12,
69         CLI_HEADER_IDX = 14,
70 };
71
72 enum {
73         STRINGS_STREAM,
74         USER_STRINGS_STREAM,
75         BLOB_STREAM,
76         GUID_STREAM,
77         TILDE_STREAM
78 };
79
80
81 #define INVALID_TABLE (0xFF)
82 /*format: number of bits, number of tables, tables{n. tables} */
83 const static unsigned char coded_index_desc[] = {
84 #define TYPEDEF_OR_REF_DESC (0)
85         2, /*bits*/
86         3, /*tables*/
87         MONO_TABLE_TYPEDEF,
88         MONO_TABLE_TYPEREF,
89         MONO_TABLE_TYPESPEC,
90
91 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
92         2, /*bits*/
93         3, /*tables*/
94         MONO_TABLE_FIELD,
95         MONO_TABLE_PARAM,
96         MONO_TABLE_PROPERTY,
97
98 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
99         5, /*bits*/
100         20, /*tables*/
101         MONO_TABLE_METHOD,
102         MONO_TABLE_FIELD,
103         MONO_TABLE_TYPEREF,
104         MONO_TABLE_TYPEDEF,
105         MONO_TABLE_PARAM,
106         MONO_TABLE_INTERFACEIMPL,
107         MONO_TABLE_MEMBERREF,
108         MONO_TABLE_MODULE,
109         MONO_TABLE_DECLSECURITY,
110         MONO_TABLE_PROPERTY, 
111         MONO_TABLE_EVENT,
112         MONO_TABLE_STANDALONESIG,
113         MONO_TABLE_MODULEREF,
114         MONO_TABLE_TYPESPEC,
115         MONO_TABLE_ASSEMBLY,
116         MONO_TABLE_ASSEMBLYREF,
117         MONO_TABLE_FILE,
118         MONO_TABLE_EXPORTEDTYPE,
119         MONO_TABLE_MANIFESTRESOURCE,
120         MONO_TABLE_GENERICPARAM,
121
122 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
123         1, /*bits*/
124         2, /*tables*/
125         MONO_TABLE_FIELD,
126         MONO_TABLE_PARAM,
127
128 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
129         2, /*bits*/
130         3, /*tables*/
131         MONO_TABLE_TYPEDEF,
132         MONO_TABLE_METHOD,
133         MONO_TABLE_ASSEMBLY,
134
135 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
136         3, /*bits*/
137         5, /*tables*/
138         MONO_TABLE_TYPEDEF,
139         MONO_TABLE_TYPEREF,
140         MONO_TABLE_MODULE,
141         MONO_TABLE_METHOD,
142         MONO_TABLE_TYPESPEC,
143
144 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
145         1, /*bits*/
146         2, /*tables*/
147         MONO_TABLE_EVENT,
148         MONO_TABLE_PROPERTY,
149
150 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
151         1, /*bits*/
152         2, /*tables*/
153         MONO_TABLE_METHOD,
154         MONO_TABLE_MEMBERREF,
155
156 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
157         1, /*bits*/
158         2, /*tables*/
159         MONO_TABLE_FIELD,
160         MONO_TABLE_METHOD,
161
162 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
163         2, /*bits*/
164         3, /*tables*/
165         MONO_TABLE_FILE,
166         MONO_TABLE_ASSEMBLYREF,
167         MONO_TABLE_EXPORTEDTYPE,
168
169 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
170         3, /*bits*/
171         5, /*tables*/
172         INVALID_TABLE,
173         INVALID_TABLE,
174         MONO_TABLE_METHOD,
175         MONO_TABLE_MEMBERREF,
176         INVALID_TABLE,
177
178 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
179         2, /*bits*/
180         4, /*tables*/
181         MONO_TABLE_MODULE,
182         MONO_TABLE_MODULEREF,
183         MONO_TABLE_ASSEMBLYREF,
184         MONO_TABLE_TYPEREF,
185
186 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
187         1, /*bits*/
188         2, /*tables*/
189         MONO_TABLE_TYPEDEF,
190         MONO_TABLE_METHOD
191 };
192
193 typedef struct {
194         guint32 rva;
195         guint32 size;
196         guint32 translated_offset;
197 } DataDirectory;
198
199 typedef struct {
200         guint32 offset;
201         guint32 size;
202 } OffsetAndSize;
203
204 typedef struct {
205         guint32 baseRVA;
206         guint32 baseOffset;
207         guint32 size;
208         guint32 rellocationsRVA;
209         guint16 numberOfRelocations;
210 } SectionHeader;
211
212 typedef struct {
213         guint32 row_count;
214         guint32 row_size;
215         guint32 offset;
216 } TableInfo;
217
218 typedef struct {
219         const char *data;
220         guint32 size;
221         GSList *errors;
222         int valid;
223         MonoImage *image;
224         gboolean report_error;
225         gboolean report_warning;
226         int stage;
227
228         DataDirectory data_directories [16];
229         guint32 section_count;
230         SectionHeader *sections;
231
232         OffsetAndSize metadata_streams [5]; //offset from begin of the image
233 } VerifyContext;
234
235 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception)    \
236         do {    \
237                 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1);      \
238                 vinfo->info.status = __status;  \
239                 vinfo->info.message = ( __msg); \
240                 vinfo->exception_type = (__exception);  \
241                 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo);     \
242         } while (0)
243
244 #define ADD_WARNING(__ctx, __msg)       \
245         do {    \
246                 if ((__ctx)->report_warning) { \
247                         ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
248                         (__ctx)->valid = 0; \
249                         return; \
250                 } \
251         } while (0)
252
253 #define ADD_ERROR(__ctx, __msg) \
254         do {    \
255                 if ((__ctx)->report_error) \
256                         ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
257                 (__ctx)->valid = 0; \
258                 return; \
259         } while (0)
260
261 #define FAIL(__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 FALSE; \
267         } while (0)
268
269 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
270
271 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
272
273 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
274 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
275
276 #if SIZEOF_VOID_P == 4
277 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
278 #else
279 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
280 #endif
281
282 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
283 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
284
285 static const char *
286 dword_align (const char *ptr)
287 {
288 #if SIZEOF_VOID_P == 8
289         return (const char *) (((guint64) (ptr + 3)) & ~3);
290 #else
291         return (const char *) (((guint32) (ptr + 3)) & ~3);
292 #endif
293 }
294
295 static guint32
296 pe_signature_offset (VerifyContext *ctx)
297 {
298         return read32 (ctx->data + 0x3c);
299 }
300
301 static guint32
302 pe_header_offset (VerifyContext *ctx)
303 {
304         return read32 (ctx->data + 0x3c) + 4;
305 }
306
307 static gboolean
308 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
309 {
310         int i;
311
312         if (rva + size < rva) //overflow
313                 return FALSE;
314
315         if (ctx->stage > STAGE_PE) {
316                 MonoCLIImageInfo *iinfo = ctx->image->image_info;
317                 const int top = iinfo->cli_section_count;
318                 MonoSectionTable *tables = iinfo->cli_section_tables;
319                 int i;
320                 
321                 for (i = 0; i < top; i++) {
322                         guint32 base = tables->st_virtual_address;
323                         guint32 end = base + tables->st_raw_data_size;
324
325                         if (rva >= base && rva + size <= end)
326                                 return TRUE;
327
328                         /*if ((addr >= tables->st_virtual_address) &&
329                             (addr < tables->st_virtual_address + tables->st_raw_data_size)){
330
331                                 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
332                         }*/
333                         tables++;
334                 }
335                 return FALSE;
336         }
337
338         if (!ctx->sections)
339                 return FALSE;
340
341         for (i = 0; i < ctx->section_count; ++i) {
342                 guint32 base = ctx->sections [i].baseRVA;
343                 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
344                 if (rva >= base && rva + size <= end)
345                         return TRUE;
346         }
347         return FALSE;
348 }
349
350 static gboolean
351 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
352 {
353         if (dir->translated_offset > offset)
354                 return FALSE;
355         if (dir->size < size)
356                 return FALSE;
357         return offset + size <= dir->translated_offset + dir->size;
358 }
359
360 static gboolean
361 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
362 {
363         if (off->offset > offset)
364                 return FALSE;
365         
366         if (off->size < size)
367                 return FALSE;
368
369         return offset + size <= off->offset + off->size;
370 }
371
372 static guint32
373 translate_rva (VerifyContext *ctx, guint32 rva)
374 {
375         int i;
376
377         if (ctx->stage > STAGE_PE)
378                 return mono_cli_rva_image_map (ctx->image, rva);
379                 
380         if (!ctx->sections)
381                 return FALSE;
382
383         for (i = 0; i < ctx->section_count; ++i) {
384                 guint32 base = ctx->sections [i].baseRVA;
385                 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
386                 if (rva >= base && rva <= end) {
387                         guint32 res = (rva - base) + ctx->sections [i].baseOffset;
388                         /* double check */
389                         return res >= ctx->size ? INVALID_OFFSET : res;
390                 }
391         }
392
393         return INVALID_OFFSET;
394 }
395
396 static void
397 verify_msdos_header (VerifyContext *ctx)
398 {
399         guint32 lfanew;
400         if (ctx->size < 128)
401                 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
402         if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
403                 ADD_ERROR (ctx,  g_strdup ("Invalid MS-DOS watermark"));
404         lfanew = pe_signature_offset (ctx);
405         if (lfanew > ctx->size - 4)
406                 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
407 }
408
409 static void
410 verify_pe_header (VerifyContext *ctx)
411 {
412         guint32 offset = pe_signature_offset (ctx);
413         const char *pe_header = ctx->data + offset;
414         if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
415                 ADD_ERROR (ctx,  g_strdup ("Invalid PE header watermark"));
416         pe_header += 4;
417         offset += 4;
418
419         if (offset > ctx->size - 20)
420                 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
421         if (read16 (pe_header) != 0x14c)
422                 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
423 }
424
425 static void
426 verify_pe_optional_header (VerifyContext *ctx)
427 {
428         guint32 offset = pe_header_offset (ctx);
429         guint32 header_size, file_alignment;
430         const char *pe_header = ctx->data + offset;
431         const char *pe_optional_header = pe_header + 20;
432
433         header_size = read16 (pe_header + 16);
434         offset += 20;
435
436         if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
437                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
438
439         if (offset > ctx->size - header_size || header_size > ctx->size)
440                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
441
442         if (read16 (pe_optional_header) == 0x10b) {
443                 if (header_size != 224)
444                         ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
445
446                 /* LAMESPEC MS plays around this value and ignore it during validation
447                 if (read32 (pe_optional_header + 28) != 0x400000)
448                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
449                 if (read32 (pe_optional_header + 32) != 0x2000)
450                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
451                 file_alignment = read32 (pe_optional_header + 36);
452                 if (file_alignment != 0x200 && file_alignment != 0x1000)
453                         ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
454                 /* All the junk in the middle is irrelevant, specially for mono. */
455                 if (read32 (pe_optional_header + 92) > 0x10)
456                         ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
457         } else {
458                 if (read16 (pe_optional_header) == 0x20B)
459                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
460                 else
461                         ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
462         }
463 }
464
465 static void
466 load_section_table (VerifyContext *ctx)
467 {
468         int i;
469         SectionHeader *sections;
470         guint32 offset =  pe_header_offset (ctx);
471         const char *ptr = ctx->data + offset;
472         guint16 num_sections = ctx->section_count = read16 (ptr + 2);
473
474         offset += 244;/*FIXME, this constant is different under PE32+*/
475         ptr += 244;
476
477         if (num_sections * 40 > ctx->size - offset)
478                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
479
480         sections = ctx->sections = g_new0 (SectionHeader, num_sections);
481         for (i = 0; i < num_sections; ++i) {
482                 sections [i].size = read32 (ptr + 8);
483                 sections [i].baseRVA = read32 (ptr + 12);
484                 sections [i].baseOffset = read32 (ptr + 20);
485                 sections [i].rellocationsRVA = read32 (ptr + 24);
486                 sections [i].numberOfRelocations = read16 (ptr + 32);
487                 ptr += 40;
488         }
489
490         ptr = ctx->data + offset; /*reset it to the beggining*/
491         for (i = 0; i < num_sections; ++i) {
492                 guint32 raw_size, flags;
493                 if (sections [i].baseOffset == 0)
494                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
495                 if (sections [i].baseOffset >= ctx->size)
496                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
497                 if (sections [i].size > ctx->size - sections [i].baseOffset)
498                         ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
499
500                 raw_size = read32 (ptr + 16);
501                 if (raw_size < sections [i].size)
502                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
503
504                 if (raw_size > ctx->size - sections [i].baseOffset)
505                         ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
506
507                 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
508                         ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
509
510                 flags = read32 (ptr + 36);
511                 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
512                 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
513                         ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
514
515                 ptr += 40;
516         }
517 }
518
519 static gboolean
520 is_valid_data_directory (int i)
521 {
522         /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
523         return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6; 
524 }
525
526 static void
527 load_data_directories (VerifyContext *ctx)
528 {
529         guint32 offset =  pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
530         const char *ptr = ctx->data + offset;
531         int i;
532
533         for (i = 0; i < 16; ++i) {
534                 guint32 rva = read32 (ptr);
535                 guint32 size = read32 (ptr + 4);
536
537                 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
538                 if (i == CERTIFICATE_TABLE_IDX) {
539                         ptr += 8;
540                         continue;
541                 }
542                 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
543                         ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
544
545                 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
546                         ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
547
548                 ctx->data_directories [i].rva = rva;
549                 ctx->data_directories [i].size = size;
550                 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
551
552                 ptr += 8;
553         }
554 }
555
556 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
557
558 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
559
560 static void
561 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
562 {
563         const char *ptr;
564         guint32 hint_table_rva;
565
566         import_rva = translate_rva (ctx, import_rva);
567         g_assert (import_rva != INVALID_OFFSET);
568
569         hint_table_rva = read32 (ctx->data + import_rva);
570         if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
571                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
572
573         hint_table_rva = translate_rva (ctx, hint_table_rva);
574         g_assert (hint_table_rva != INVALID_OFFSET);
575         ptr = ctx->data + hint_table_rva + 2;
576
577         if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
578                 char name[SIZE_OF_CORMAIN];
579                 memcpy (name, ptr, SIZE_OF_CORMAIN);
580                 name [SIZE_OF_CORMAIN - 1] = 0;
581                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
582         }
583 }
584
585 static void
586 verify_import_table (VerifyContext *ctx)
587 {
588         DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
589         guint32 offset = it.translated_offset;
590         const char *ptr = ctx->data + offset;
591         guint32 name_rva, ilt_rva, iat_rva;
592
593         g_assert (offset != INVALID_OFFSET);
594
595         if (it.size < 40)
596                 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
597
598         ilt_rva = read32 (ptr);
599         if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
600                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
601
602         name_rva = read32 (ptr + 12);
603         if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
604                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
605
606         iat_rva = read32 (ptr + 16);
607         if (iat_rva) {
608                 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
609                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
610
611                 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
612                         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));
613         }
614
615         if (name_rva) {
616                 name_rva = translate_rva (ctx, name_rva);
617                 g_assert (name_rva != INVALID_OFFSET);
618                 ptr = ctx->data + name_rva;
619         
620                 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
621                         char name[SIZE_OF_MSCOREE];
622                         memcpy (name, ptr, SIZE_OF_MSCOREE);
623                         name [SIZE_OF_MSCOREE - 1] = 0;
624                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
625                 }
626         }
627         
628         if (ilt_rva) {
629                 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
630                 CHECK_ERROR ();
631         }
632
633         if (iat_rva)
634                 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
635 }
636
637 static void
638 verify_resources_table (VerifyContext *ctx)
639 {
640         DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
641         guint32 offset;
642         guint16 named_entries, id_entries;
643         const char *ptr, *root, *end;
644
645         if (it.rva == 0)
646                 return;
647
648         if (it.size < 16)
649                 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));
650
651         offset = it.translated_offset;
652         root = ptr = ctx->data + offset;
653         end = root + it.size;
654
655         g_assert (offset != INVALID_OFFSET);
656
657         named_entries = read16 (ptr + 12);
658         id_entries = read16 (ptr + 14);
659
660         if ((named_entries + id_entries) * 8 + 16 > it.size)
661                 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));
662
663         /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource () 
664         if (named_entries || id_entries)
665                 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
666         */
667 }
668
669 /*----------nothing from here on can use data_directory---*/
670
671 static DataDirectory
672 get_data_dir (VerifyContext *ctx, int idx)
673 {
674         MonoCLIImageInfo *iinfo = ctx->image->image_info;
675         MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
676         DataDirectory res;
677
678         entry += idx;
679         res.rva = entry->rva;
680         res.size = entry->size;
681         res.translated_offset = translate_rva (ctx, res.rva);
682         return res;
683
684 }
685 static void
686 verify_cli_header (VerifyContext *ctx)
687 {
688         DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
689         guint32 offset;
690         const char *ptr;
691         int i;
692
693         if (it.rva == 0)
694                 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
695
696         if (it.size != 72)
697                 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
698
699         offset = it.translated_offset;
700         ptr = ctx->data + offset;
701
702         g_assert (offset != INVALID_OFFSET);
703
704         if (read16 (ptr) != 72)
705                 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
706
707         if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
708                 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
709
710
711         if (!read32 (ptr + 8) || !read32 (ptr + 12))
712                 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
713
714         if ((read32 (ptr + 16) & ~0x0001000B) != 0)
715                 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
716
717         ptr += 24;
718         for (i = 0; i < 6; ++i) {
719                 guint32 rva = read32 (ptr);
720                 guint32 size = read32 (ptr + 4);
721
722                 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
723                         ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
724
725                 ptr += 8;
726
727                 if (rva && i > 1)
728                         ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
729         }
730 }
731
732 static guint32
733 pad4 (guint32 offset)
734 {
735         if (offset & 0x3) //pad to the next 4 byte boundary
736                 offset = (offset & ~0x3) + 4;
737         return offset;
738 }
739
740 static void
741 verify_metadata_header (VerifyContext *ctx)
742 {
743         int i;
744         DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
745         guint32 offset;
746         const char *ptr;
747
748         offset = it.translated_offset;
749         ptr = ctx->data + offset;
750         g_assert (offset != INVALID_OFFSET);
751
752         //build a directory entry for the metadata root
753         ptr += 8;
754         it.rva = read32 (ptr);
755         ptr += 4;
756         it.size = read32 (ptr);
757         it.translated_offset = offset = translate_rva (ctx, it.rva);
758
759         ptr = ctx->data + offset;
760         g_assert (offset != INVALID_OFFSET);
761
762         if (it.size < 20)
763                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
764
765         if (read32 (ptr) != 0x424A5342)
766                 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
767
768         offset = pad4 (offset + 16 + read32 (ptr + 12));
769
770         if (!bounds_check_datadir (&it, offset, 4))
771                 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));
772
773         ptr = ctx->data + offset; //move to streams header 
774
775         if (read16 (ptr + 2) < 3)
776                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob"));
777
778         ptr += 4;
779         offset += 4;
780
781         for (i = 0; i < 5; ++i) {
782                 guint32 stream_off, stream_size;
783                 int string_size, stream_idx;
784
785                 if (!bounds_check_datadir (&it, offset, 8))
786                         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));
787
788                 stream_off = it.translated_offset + read32 (ptr);
789                 stream_size = read32 (ptr + 4);
790
791                 if (!bounds_check_datadir (&it,  stream_off, stream_size))
792                         ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
793
794                 ptr += 8;
795                 offset += 8;
796
797                 for (string_size = 0; string_size < 32; ++string_size) {
798                         if (!bounds_check_datadir (&it, offset++, 1))
799                                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
800                         if (!ptr [string_size])
801                                 break;
802                 }
803
804                 if (ptr [string_size])
805                         ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
806
807                 if (!strncmp ("#Strings", ptr, 9))
808                         stream_idx = STRINGS_STREAM;
809                 else if (!strncmp ("#US", ptr, 4))
810                         stream_idx = USER_STRINGS_STREAM;
811                 else if (!strncmp ("#Blob", ptr, 6))
812                         stream_idx = BLOB_STREAM;
813                 else if (!strncmp ("#GUID", ptr, 6))
814                         stream_idx = GUID_STREAM;
815                 else if (!strncmp ("#~", ptr, 3))
816                         stream_idx = TILDE_STREAM;
817                 else
818                         ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
819
820                 if (ctx->metadata_streams [stream_idx].offset != 0)
821                         ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
822
823                 ctx->metadata_streams [stream_idx].offset = stream_off;
824                 ctx->metadata_streams [stream_idx].size = stream_size;
825
826                 offset = pad4 (offset);
827                 ptr = ctx->data + offset;
828         }
829
830         if (!ctx->metadata_streams [TILDE_STREAM].size)
831                 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
832         if (!ctx->metadata_streams [GUID_STREAM].size)
833                 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
834         if (!ctx->metadata_streams [BLOB_STREAM].size)
835                 ADD_ERROR (ctx, g_strdup_printf ("Metadata blob stream missing"));
836                 
837 }
838
839 static void
840 verify_tables_schema (VerifyContext *ctx)
841 {
842         OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
843         unsigned offset = tables_area.offset;
844         const char *ptr = ctx->data + offset;
845         guint64 valid_tables;
846         guint32 count;
847         int i;
848
849         //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
850         if (tables_area.size < 24)
851                 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
852
853         //printf ("ptr %x %x\n", ptr[4], ptr[5]);
854         if (ptr [4] != 2 && ptr [4] != 1)
855                 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
856         if (ptr [5] != 0)
857                 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
858
859         if ((ptr [6] & ~0x7) != 0)
860                 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]));
861
862         valid_tables = read64 (ptr + 8);
863         count = 0;
864         for (i = 0; i < 64; ++i) {
865                 if (!(valid_tables & ((guint64)1 << i)))
866                         continue;
867
868                 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
869                   Unused: 0x1E 0x1F 0x2D-0x3F
870                   We don't care about the MS extensions.*/
871                 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
872                         ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
873                 if (i == 0x1E || i == 0x1F || i >= 0x2D)
874                         ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
875                 ++count;
876         }
877
878         if (tables_area.size < 24 + count * 4)
879                 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));
880         ptr += 24;
881
882         for (i = 0; i < 64; ++i) {
883                 if (valid_tables & ((guint64)1 << i)) {
884                         guint32 row_count = read32 (ptr);
885                         if (row_count > (1 << 24) - 1)
886                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
887                         ptr += 4;
888                 }
889         }
890 }
891
892 /*----------nothing from here on can use data_directory or metadata_streams ---*/
893
894 static guint32
895 get_col_offset (VerifyContext *ctx, int table, int column)
896 {
897         guint32 bitfield = ctx->image->tables [table].size_bitfield;
898         guint32 offset = 0;
899
900         while (column-- > 0)
901                 offset += mono_metadata_table_size (bitfield, column);
902
903         return offset;
904 }
905
906 static guint32
907 get_col_size (VerifyContext *ctx, int table, int column)
908 {
909         return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
910 }
911
912 static OffsetAndSize
913 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
914 {
915         OffsetAndSize res;
916         res.offset = header->data - ctx->data;
917         res.size = header->size;
918
919         return res;
920 }
921
922 static gboolean
923 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
924 {
925         OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
926         glong length;
927         const char *data = ctx->data + strings.offset;
928
929         if (offset >= strings.size)
930                 return FALSE;
931         if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing  
932                 return FALSE;
933
934         if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
935                 return FALSE;
936         return allow_empty || length > 0;
937 }
938
939 static gboolean
940 is_valid_string (VerifyContext *ctx, guint32 offset)
941 {
942         return is_valid_string_full (ctx, offset, TRUE);
943 }
944
945 static gboolean
946 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
947 {
948         return is_valid_string_full (ctx, offset, FALSE);
949 }
950
951 static gboolean
952 is_valid_guid (VerifyContext *ctx, guint32 offset)
953 {
954         OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
955         return guids.size >= 8 && guids.size - 8 >= offset;
956 }
957
958 static guint32
959 get_coded_index_token (int token_kind, guint32 coded_token)
960 {
961         guint32 bits = coded_index_desc [token_kind];
962         return coded_token >> bits;
963 }
964
965 static guint32
966 get_coded_index_table (int kind, guint32 coded_token)
967 {
968         guint32 idx, bits = coded_index_desc [kind];
969         kind += 2;
970         idx = coded_token & ((1 << bits) - 1);
971         return coded_index_desc [kind + idx];
972 }
973
974 static guint32
975 make_coded_token (int kind, guint32 table, guint32 table_idx)
976 {
977         guint32 bits = coded_index_desc [kind++];
978         guint32 tables = coded_index_desc [kind++];
979         guint32 i;
980         for (i = 0; i < tables; ++i) {
981                 if (coded_index_desc [kind++] == table)
982                         return ((table_idx + 1) << bits) | i; 
983         }
984         g_assert_not_reached ();
985         return -1;
986 }
987
988 static gboolean
989 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
990 {
991         guint32 bits = coded_index_desc [token_kind++];
992         guint32 table_count = coded_index_desc [token_kind++];
993         guint32 table = coded_token & ((1 << bits) - 1);
994         guint32 token = coded_token >> bits;
995
996         if (table >= table_count)
997                 return FALSE;
998
999         /*token_kind points to the first table idx*/
1000         table = coded_index_desc [token_kind + table];
1001
1002         if (table == INVALID_TABLE)
1003                 return FALSE;
1004         return token <= ctx->image->tables [table].rows;
1005 }
1006
1007 typedef struct {
1008         guint32 token;
1009         guint32 col_size;
1010         guint32 col_offset;
1011         MonoTableInfo *table;
1012 } RowLocator;
1013
1014 static int
1015 token_locator (const void *a, const void *b)
1016 {
1017         RowLocator *loc = (RowLocator *)a;
1018         unsigned const char *row = (unsigned const char *)b;
1019         guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1020
1021         VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1022         return (int)loc->token - (int)token;
1023 }
1024
1025 static int
1026 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1027 {
1028         MonoTableInfo *tinfo = &ctx->image->tables [table];
1029         RowLocator locator;
1030         const char *res, *base;
1031         locator.token = coded_token;
1032         locator.col_offset = get_col_offset (ctx, table, column);
1033         locator.col_size = get_col_size (ctx, table, column);
1034         locator.table = tinfo;
1035
1036         base = tinfo->base;
1037
1038         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) );
1039         res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1040         if (!res)
1041                 return -1;
1042
1043         return (res - base) / tinfo->row_size;
1044 }
1045
1046 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1047 static const char*
1048 get_string_ptr (VerifyContext *ctx, guint offset)
1049 {
1050         return ctx->image->heap_strings.data + offset;
1051 }
1052
1053 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1054 static int
1055 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1056 {
1057         if (offset == 0)
1058                 return strcmp (str, "");
1059
1060         return strcmp (str, get_string_ptr (ctx, offset));
1061 }
1062
1063 static gboolean
1064 mono_verifier_is_corlib (MonoImage *image)
1065 {
1066         gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ? 
1067                         TRUE : mono_security_core_clr_is_platform_image (image);
1068
1069         return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1070 }
1071
1072 static gboolean
1073 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1074 {
1075         return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1076 }
1077
1078 static gboolean
1079 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1080 {
1081         unsigned char b;
1082         const unsigned char *ptr = (const unsigned char *)_ptr;
1083
1084         if (!available)
1085                 return FALSE;
1086
1087         b = *ptr;
1088         *value = *size = 0;
1089         
1090         if ((b & 0x80) == 0) {
1091                 *size = 1;
1092                 *value = b;
1093         } else if ((b & 0x40) == 0) {
1094                 if (available < 2)
1095                         return FALSE;
1096                 *size = 2;
1097                 *value = ((b & 0x3f) << 8 | ptr [1]);
1098         } else {
1099                 if (available < 4)
1100                         return FALSE;
1101                 *size = 4;
1102                 *value  = ((b & 0x1f) << 24) |
1103                         (ptr [1] << 16) |
1104                         (ptr [2] << 8) |
1105                         ptr [3];
1106         }
1107
1108         return TRUE;
1109 }
1110
1111 static gboolean
1112 decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
1113 {
1114         MonoStreamHeader blob = ctx->image->heap_blob;
1115         guint32 value, enc_size;
1116
1117         if (offset >= blob.size)
1118                 return FALSE;
1119
1120         if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1121                 return FALSE;
1122
1123         if (offset + enc_size + value < offset)
1124                 return FALSE;
1125
1126         if (offset + enc_size + value > blob.size)
1127                 return FALSE;
1128
1129         *size = value;
1130         *first_byte = blob.data + offset + enc_size;
1131         return TRUE;
1132 }
1133
1134 static gboolean
1135 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1136 {
1137         const char *ptr = *_ptr;
1138         if (ptr + size > limit)
1139                 return FALSE;
1140         switch (size) {
1141         case 1:
1142                 *dest = *((guint8*)ptr);
1143                 ++ptr;
1144                 break;
1145         case 2:
1146                 *dest = read16 (ptr);
1147                 ptr += 2;
1148                 break;
1149         case 4:
1150                 *dest = read32 (ptr);
1151                 ptr += 4;
1152                 break;
1153         }
1154         *_ptr = ptr;
1155         return TRUE;
1156 }
1157
1158 static gboolean
1159 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1160 {
1161         unsigned size = 0;
1162         const char *ptr = *_ptr;
1163         gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1164         *_ptr = ptr + size;
1165         return res;
1166 }
1167
1168 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1169 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1170 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1171 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1172
1173 static gboolean
1174 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1175
1176 static gboolean
1177 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1178
1179 static gboolean
1180 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1181 {
1182         const char *ptr = *_ptr;
1183         unsigned type = 0;
1184         unsigned token = 0;
1185
1186         while (TRUE) {
1187                 if (!safe_read8 (type, ptr, end))
1188                         FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1189         
1190                 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1191                         --ptr;
1192                         break;
1193                 }
1194         
1195                 if (!safe_read_cint (token, ptr, end))
1196                         FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1197         
1198                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1199                         FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1200         }
1201
1202         *_ptr = ptr;
1203         return TRUE;
1204 }
1205
1206 static gboolean
1207 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1208 {
1209         const char *ptr = *_ptr;
1210         unsigned val = 0;
1211         unsigned size, num, i;
1212
1213         if (!safe_read8 (val, ptr, end))
1214                 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1215
1216         if (val == 0)
1217                 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1218
1219         if (!safe_read_cint (size, ptr, end))
1220                 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1221
1222         for (i = 0; i < size; ++i) {
1223                 if (!safe_read_cint (num, ptr, end))
1224                         FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1225         }
1226
1227         if (!safe_read_cint (size, ptr, end))
1228                 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1229
1230         for (i = 0; i < size; ++i) {
1231                 if (!safe_read_cint (num, ptr, end))
1232                         FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1233         }
1234
1235         *_ptr = ptr;
1236         return TRUE;
1237 }
1238
1239 static gboolean
1240 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1241 {
1242         const char *ptr = *_ptr;
1243         unsigned type;
1244         unsigned count, token, i;
1245
1246         if (!safe_read8 (type, ptr, end))
1247                 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1248
1249         if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1250                 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1251
1252         if (!safe_read_cint (token, ptr, end))
1253                 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1254
1255         if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1256                 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1257
1258         if (!safe_read_cint (count, ptr, end))
1259                 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1260
1261         if (count == 0)
1262                 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1263
1264         for (i = 0; i < count; ++i) {
1265                 if (!parse_type (ctx, &ptr, end))
1266                         FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1267         }
1268         *_ptr = ptr;
1269         return TRUE;
1270 }
1271
1272 static gboolean
1273 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1274 {
1275         const char *ptr = *_ptr;
1276         unsigned type;
1277         unsigned token = 0;
1278
1279         if (!safe_read8 (type, ptr, end))
1280                 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1281
1282         if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1283                 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1284                 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1285                 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1286                 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1287
1288         switch (type) {
1289         case MONO_TYPE_PTR:
1290                 if (!parse_custom_mods (ctx, &ptr, end))
1291                         FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1292
1293                 if (!safe_read8 (type, ptr, end))
1294                         FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1295
1296                 if (type != MONO_TYPE_VOID) {
1297                         --ptr;
1298                         if (!parse_type (ctx, &ptr, end))
1299                                 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1300                 }
1301                 break;
1302
1303         case MONO_TYPE_VALUETYPE:
1304         case MONO_TYPE_CLASS:
1305                 if (!safe_read_cint (token, ptr, end))
1306                         FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1307         
1308                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1309                         FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1310                 break;
1311
1312         case MONO_TYPE_VAR:
1313         case MONO_TYPE_MVAR:
1314                 if (!safe_read_cint (token, ptr, end))
1315                         FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1316                 break;
1317
1318         case MONO_TYPE_ARRAY:
1319                 if (!parse_type (ctx, &ptr, end))
1320                         FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1321                 if (!parse_array_shape (ctx, &ptr, end))
1322                         FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1323                 break;
1324
1325         case MONO_TYPE_GENERICINST:
1326                 if (!parse_generic_inst (ctx, &ptr, end))
1327                         FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1328                 break;
1329
1330         case MONO_TYPE_FNPTR:
1331                 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1332                         FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1333                 break;
1334
1335         case MONO_TYPE_SZARRAY:
1336                 if (!parse_custom_mods (ctx, &ptr, end))
1337                         FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1338                 if (!parse_type (ctx, &ptr, end))
1339                         FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1340                 break;
1341         }
1342         *_ptr = ptr;
1343         return TRUE;
1344 }
1345
1346 static gboolean
1347 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1348 {
1349         const char *ptr;
1350         unsigned type = 0;
1351
1352         if (!parse_custom_mods (ctx, _ptr, end))
1353                 return FALSE;
1354
1355         ptr = *_ptr;
1356         if (!safe_read8 (type, ptr, end))
1357                 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1358
1359         if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1360                 *_ptr = ptr;
1361                 return TRUE;
1362         }
1363
1364         //it's a byref, update the cursor ptr
1365         if (type == MONO_TYPE_BYREF)
1366                 *_ptr = ptr;
1367
1368         return parse_type (ctx, _ptr, end);
1369 }
1370
1371 static gboolean
1372 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1373 {
1374         const char *ptr;
1375         unsigned type = 0;
1376
1377         if (!parse_custom_mods (ctx, _ptr, end))
1378                 return FALSE;
1379
1380         ptr = *_ptr;
1381         if (!safe_read8 (type, ptr, end))
1382                 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1383
1384         if (type == MONO_TYPE_TYPEDBYREF) {
1385                 *_ptr = ptr;
1386                 return TRUE;
1387         }
1388
1389         //it's a byref, update the cursor ptr
1390         if (type == MONO_TYPE_BYREF)
1391                 *_ptr = ptr;
1392
1393         return parse_type (ctx, _ptr, end);
1394 }
1395
1396 static gboolean
1397 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1398 {
1399         unsigned cconv = 0;
1400         unsigned param_count = 0, gparam_count = 0, type = 0, i;
1401         const char *ptr = *_ptr;
1402         gboolean saw_sentinel = FALSE;
1403
1404         if (!safe_read8 (cconv, ptr, end))
1405                 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1406
1407         if (cconv & 0x80)
1408                 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1409
1410         if (allow_unmanaged) {
1411                 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1412                         FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1413         } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1414                 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1415
1416         if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1417                 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1418
1419         if ((cconv & 0x10) && gparam_count == 0)
1420                 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1421
1422         if (allow_unmanaged && (cconv & 0x10))
1423                 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1424
1425         if (!safe_read_cint (param_count, ptr, end))
1426                 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1427
1428         if (!parse_return_type (ctx, &ptr, end))
1429                 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1430
1431         for (i = 0; i < param_count; ++i) {
1432                 if (allow_sentinel) {
1433                         if (!safe_read8 (type, ptr, end))
1434                                 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1435
1436                         if (type == MONO_TYPE_SENTINEL) {
1437                                 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1438                                         FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1439
1440                                 if (saw_sentinel)
1441                                         FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1442
1443                                 saw_sentinel = TRUE;
1444                         } else {
1445                                 --ptr;
1446                         }
1447                 }
1448
1449                 if (!parse_param (ctx, &ptr, end))
1450                         FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1451         }
1452
1453         *_ptr = ptr;
1454         return TRUE;
1455 }
1456
1457 static gboolean
1458 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1459 {
1460         unsigned sig = 0;
1461         unsigned param_count = 0, i;
1462         const char *ptr = *_ptr;
1463
1464         if (!safe_read8 (sig, ptr, end))
1465                 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1466
1467         if (sig != 0x08 && sig != 0x28)
1468                 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1469
1470         if (!safe_read_cint (param_count, ptr, end))
1471                 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1472
1473         if (!parse_custom_mods (ctx, &ptr, end))
1474                 return FALSE;
1475
1476         if (!parse_type (ctx, &ptr, end))
1477                 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1478
1479         for (i = 0; i < param_count; ++i) {
1480                 if (!parse_type (ctx, &ptr, end))
1481                         FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1482         }
1483
1484         *_ptr = ptr;
1485         return TRUE;
1486 }
1487
1488 static gboolean
1489 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1490 {
1491         const char *ptr = *_ptr;
1492         unsigned signature = 0;
1493
1494         if (!safe_read8 (signature, ptr, end))
1495                 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1496
1497         if (signature != 0x06)
1498                 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1499
1500         if (!parse_custom_mods (ctx, &ptr, end))
1501                 return FALSE;
1502
1503         if (safe_read8 (signature, ptr, end)) {
1504                 if (signature != MONO_TYPE_BYREF)
1505                         --ptr;
1506         }
1507         *_ptr = ptr;
1508
1509         return parse_type (ctx, _ptr, end);
1510 }
1511
1512 static gboolean
1513 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1514 {
1515         unsigned sig = 0;
1516         unsigned locals_count = 0, i;
1517         const char *ptr = *_ptr;        
1518
1519         if (!safe_read8 (sig, ptr, end))
1520                 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1521
1522         if (sig != 0x07)
1523                 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1524
1525         if (!safe_read_cint (locals_count, ptr, end))
1526                 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1527
1528         /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1529         if (locals_count == 0)
1530                 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1531         */
1532
1533         for (i = 0; i < locals_count; ++i) {
1534                 if (!safe_read8 (sig, ptr, end))
1535                         FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1536
1537                 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1538                         if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1539                                 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1540                         if (!safe_read8 (sig, ptr, end))
1541                                 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1542                 }
1543
1544                 if (sig == MONO_TYPE_BYREF) {
1545                         if (!safe_read8 (sig, ptr, end))
1546                                 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1547                         if (sig == MONO_TYPE_TYPEDBYREF)
1548                                 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1549                 }
1550
1551                 if (sig == MONO_TYPE_TYPEDBYREF)
1552                         continue;
1553
1554                 --ptr;
1555
1556                 if (!parse_type (ctx, &ptr, end))
1557                         FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1558         }
1559
1560         *_ptr = ptr;
1561         return TRUE;
1562 }
1563
1564 static gboolean
1565 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1566 {
1567         int size = 0;
1568         unsigned signature = 0;
1569         const char *ptr = NULL, *end;
1570
1571         if (!decode_signature_header (ctx, offset, &size, &ptr))
1572                 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1573         end = ptr + size;
1574
1575         if (!safe_read8 (signature, ptr, end))
1576                 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1577
1578         if (signature != 6)
1579                 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1580         --ptr;
1581
1582         return parse_field (ctx, &ptr, end);
1583 }
1584
1585 static gboolean
1586 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1587 {
1588         int size = 0;
1589         const char *ptr = NULL, *end;
1590
1591         if (!decode_signature_header (ctx, offset, &size, &ptr))
1592                 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1593         end = ptr + size;
1594
1595         return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1596 }
1597
1598 static gboolean
1599 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1600 {
1601         int size = 0;
1602         unsigned signature = 0;
1603         const char *ptr = NULL, *end;
1604
1605         if (!decode_signature_header (ctx, offset, &size, &ptr))
1606                 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1607         end = ptr + size;
1608
1609         if (!safe_read8 (signature, ptr, end))
1610                 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1611         --ptr;
1612
1613         if (signature == 0x06)
1614                 return parse_field (ctx, &ptr, end);
1615
1616         return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1617 }
1618
1619 static gboolean
1620 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1621 {
1622         int size = 0;
1623         unsigned prolog = 0;
1624         const char *ptr = NULL, *end;
1625
1626         if (!offset)
1627                 return TRUE;
1628
1629         if (!decode_signature_header (ctx, offset, &size, &ptr))
1630                 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1631         end = ptr + size;
1632
1633         if (!safe_read16 (prolog, ptr, end))
1634                 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1635
1636         if (prolog != 1)
1637                 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1638                 
1639         return TRUE;
1640 }
1641
1642 static gboolean
1643 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1644 {
1645         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1646         //TODO do proper verification
1647         return blob.size >= 1 && blob.size - 1 >= offset;
1648 }
1649
1650 static gboolean
1651 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1652 {
1653         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1654         //TODO do proper verification
1655         return blob.size >= 1 && blob.size - 1 >= offset;
1656 }
1657
1658 static gboolean
1659 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1660 {
1661         int size = 0;
1662         unsigned signature = 0;
1663         const char *ptr = NULL, *end;
1664
1665         if (!decode_signature_header (ctx, offset, &size, &ptr))
1666                 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1667         end = ptr + size;
1668
1669         if (!safe_read8 (signature, ptr, end))
1670                 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1671
1672         --ptr;
1673         if (signature == 0x07)
1674                 return parse_locals_signature (ctx, &ptr, end);
1675         return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1676 }
1677
1678 static gboolean
1679 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1680 {
1681         int size = 0;
1682         const char *ptr = NULL, *end;
1683
1684         if (!decode_signature_header (ctx, offset, &size, &ptr))
1685                 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
1686         end = ptr + size;
1687
1688         return parse_property_signature (ctx, &ptr, end);
1689 }
1690
1691 static gboolean
1692 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1693 {
1694         int size = 0;
1695         const char *ptr = NULL, *end;
1696         unsigned type = 0;
1697         
1698
1699         if (!decode_signature_header (ctx, offset, &size, &ptr))
1700                 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
1701         end = ptr + size;
1702
1703         if (!parse_custom_mods (ctx, &ptr, end))
1704                 return FALSE;
1705
1706         if (!safe_read8 (type, ptr, end))
1707                 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
1708
1709         if (type == MONO_TYPE_BYREF) {
1710                 if (!safe_read8 (type, ptr, end)) 
1711                         FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
1712                 if (type == MONO_TYPE_TYPEDBYREF)
1713                         FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
1714         }
1715         
1716         if (type == MONO_TYPE_TYPEDBYREF)
1717                 return TRUE;
1718
1719         --ptr;
1720         return parse_type (ctx, &ptr, end);
1721 }
1722
1723 static gboolean
1724 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1725 {
1726         int size = 0;
1727         const char *ptr = NULL, *end;
1728         unsigned type = 0;
1729         unsigned count = 0, i;
1730
1731         if (!decode_signature_header (ctx, offset, &size, &ptr))
1732                 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
1733         end = ptr + size;
1734
1735         if (!safe_read8 (type, ptr, end))
1736                 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
1737
1738         if (type != 0x0A)
1739                 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
1740
1741         if (!safe_read_cint (count, ptr, end))
1742                 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
1743
1744         if (!count)
1745                 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
1746
1747         for (i = 0; i < count; ++i) {
1748                 if (!parse_type (ctx, &ptr, end))
1749                         FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
1750         }
1751         return TRUE;
1752 }
1753
1754 static gboolean
1755 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
1756 {
1757         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1758         guint32 entry_size, bytes;
1759
1760         if (blob.size < offset)
1761                 return FALSE;
1762
1763         if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1764                 return FALSE;
1765
1766         if (entry_size < minsize)
1767                 return FALSE;
1768
1769         if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
1770                 return FALSE;
1771         entry_size += bytes;
1772
1773         return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
1774 }
1775
1776 static gboolean
1777 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1778 {
1779         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1780         guint32 size, entry_size, bytes;
1781
1782         if (blob.size < offset)
1783                 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
1784         
1785         if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1786                 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
1787
1788         if (type == MONO_TYPE_STRING) {
1789                 //String is encoded as: compressed_int:len len *bytes
1790                 offset += bytes;
1791
1792                 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
1793                         FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));  
1794
1795                 return TRUE;
1796         }
1797
1798         switch (type) {
1799         case MONO_TYPE_BOOLEAN:
1800         case MONO_TYPE_I1:
1801         case MONO_TYPE_U1:
1802                 size = 1;
1803                 break;
1804         case MONO_TYPE_CHAR:
1805         case MONO_TYPE_I2:
1806         case MONO_TYPE_U2:
1807                 size = 2;
1808                 break;
1809         case MONO_TYPE_I4:
1810         case MONO_TYPE_U4:
1811         case MONO_TYPE_R4:
1812         case MONO_TYPE_CLASS:
1813                 size = 4;
1814                 break;
1815
1816         case MONO_TYPE_I8:
1817         case MONO_TYPE_U8:
1818         case MONO_TYPE_R8:
1819                 size = 8;
1820                 break;
1821         default:
1822                 g_assert_not_reached ();
1823         }
1824
1825         if (size != entry_size)
1826                 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
1827
1828         offset += bytes;
1829
1830         if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
1831                 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
1832
1833         if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
1834                 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
1835         return TRUE;
1836 }
1837
1838 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
1839 //only 0x01, 0x40 and 0x80 are allowed
1840 #define SECTION_HEADER_INVALID_FLAGS 0x3E
1841
1842 static gboolean
1843 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1844 {
1845         unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
1846         unsigned header = 0;
1847         unsigned fat_header = 0, size = 0, max_stack;
1848         const char *ptr = NULL, *end;
1849
1850         if (offset == INVALID_ADDRESS)
1851                 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
1852
1853         ptr = ctx->data + offset;
1854         end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
1855
1856         if (!safe_read8 (header, ptr, end))
1857                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
1858
1859         switch (header & 0x3) {
1860         case 0:
1861         case 1:
1862                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
1863         case 2:
1864                 header >>= 2;
1865                 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end)) 
1866                         FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
1867                 return TRUE;
1868         }
1869         //FAT HEADER
1870         --ptr;
1871         if (!safe_read16 (fat_header, ptr, end))
1872                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
1873
1874         size = (fat_header >> 12) & 0xF;
1875         if (size != 3)
1876                 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
1877
1878         if (!safe_read16 (max_stack, ptr, end))
1879                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
1880
1881         if (!safe_read32 (code_size, ptr, end))
1882                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
1883
1884         if (!safe_read32 (local_vars_tok, ptr, end))
1885                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
1886
1887         if (local_vars_tok) {
1888                 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
1889                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
1890                 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)   
1891                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
1892         }
1893
1894         if (fat_header & FAT_HEADER_INVALID_FLAGS)
1895                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
1896
1897         if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
1898                 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
1899
1900         if (!(fat_header & 0x08))
1901                 return TRUE;
1902
1903         ptr += code_size;
1904
1905         do {
1906                 unsigned section_header = 0, section_size = 0;
1907                 gboolean is_fat;
1908
1909                 ptr = dword_align (ptr);
1910                 if (!safe_read32 (section_header, ptr, end))
1911                         FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
1912
1913                 if (section_header & SECTION_HEADER_INVALID_FLAGS)
1914                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
1915                         
1916                 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
1917                 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
1918
1919                 if (section_size < 4)
1920                         FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
1921
1922                 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
1923                         FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
1924
1925                 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
1926                         guint32 i, clauses = section_size / (is_fat ? 24 : 12);
1927                         /*
1928                                 LAMEIMPL: MS emits section_size without accounting for header size.
1929                                 Mono does as the spec says. section_size is header + section
1930                                 MS's peverify happily accepts both. 
1931                         */
1932                         if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
1933                                 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)));
1934
1935                         /* only verify the class token is verified as the rest is done by the IL verifier*/
1936                         for (i = 0; i < clauses; ++i) {
1937                                 unsigned flags = *(unsigned char*)ptr;
1938                                 unsigned class_token = 0;
1939                                 ptr += (is_fat ? 20 : 8);
1940                                 if (!safe_read32 (class_token, ptr, end))
1941                                         FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
1942                                 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
1943                                         guint table = mono_metadata_token_table (class_token);
1944                                         if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
1945                                                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
1946                                         if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
1947                                                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
1948                                 }
1949                         }
1950                 }
1951
1952                 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
1953                         break;
1954         } while (1);
1955         return TRUE;
1956 }
1957
1958 static void
1959 verify_module_table (VerifyContext *ctx)
1960 {
1961         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1962         guint32 data [MONO_MODULE_SIZE];
1963
1964         if (table->rows != 1)
1965                 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1966
1967         mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1968
1969         if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1970                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1971
1972         if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1973                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1974
1975         if (data [MONO_MODULE_ENC] != 0)
1976                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1977
1978         if (data [MONO_MODULE_ENCBASE] != 0)
1979                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1980 }
1981
1982 static void
1983 verify_typeref_table (VerifyContext *ctx)
1984 {
1985         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1986         guint32 data [MONO_TYPEREF_SIZE];
1987         int i;
1988
1989         for (i = 0; i < table->rows; ++i) {
1990                 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1991                 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1992                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1993                 
1994                 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1995                         ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1996
1997                 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1998                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1999
2000                 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2001                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
2002         }
2003 }
2004
2005 /*bits 9,11,14,15,19,21,24-31 */
2006 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2007 static void
2008 verify_typedef_table (VerifyContext *ctx)
2009 {
2010         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2011         guint32 data [MONO_TYPEDEF_SIZE];
2012         guint32 fieldlist = 1, methodlist = 1, visibility;
2013         int i;
2014
2015         if (table->rows == 0)
2016                 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2017
2018         for (i = 0; i < table->rows; ++i) {
2019                 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2020                 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2021                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2022
2023                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2024                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2025
2026                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2027                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2028
2029                 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2030                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2031
2032                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2033                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2034
2035                 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2036                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2037
2038                 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2039                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2040
2041                 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2042                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2043
2044                 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2045                 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2046                         search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2047                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2048
2049                 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2050                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2051
2052                 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2053                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2054
2055                 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2056                         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));
2057
2058                 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2059                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2060
2061                 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2062                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2063
2064                 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2065                         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));
2066
2067                 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2068                 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2069         }
2070 }
2071
2072 static void
2073 verify_typedef_table_full (VerifyContext *ctx)
2074 {
2075         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2076         guint32 data [MONO_TYPEDEF_SIZE];
2077         int i;
2078
2079         if (table->rows == 0)
2080                 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2081
2082         for (i = 0; i < table->rows; ++i) {
2083                 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2084
2085                 if (i == 0) {
2086                         if (data [MONO_TYPEDEF_EXTENDS] != 0)
2087                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2088                         continue;
2089                 }
2090
2091                 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2092                         if (data [MONO_TYPEDEF_EXTENDS])
2093                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2094                 } else {
2095                         gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2096                         gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2097
2098                         if (is_sys_obj) {
2099                                 if (has_parent)
2100                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2101                         } else {
2102                                 if (!has_parent) {
2103                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2104                                 }
2105                         }
2106                 }
2107         }
2108 }
2109
2110 /*bits 3,11,14 */
2111 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2112 static void
2113 verify_field_table (VerifyContext *ctx)
2114 {
2115         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2116         guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2117         int i;
2118
2119         module_field_list = (guint32)-1;
2120         if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2121                 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2122                 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2123         }
2124         
2125         for (i = 0; i < table->rows; ++i) {
2126                 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2127                 flags = data [MONO_FIELD_FLAGS];
2128
2129                 if (flags & INVALID_FIELD_FLAG_BITS)
2130                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2131
2132                 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)         
2133                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2134
2135                 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2136                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2137
2138                 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2139                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2140
2141                 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2142                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2143
2144                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2145                                 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2146                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2147
2148                 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2149                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2150                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2151
2152                 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2153                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2154                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2155
2156                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2157                                 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2158                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2159
2160                 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2161                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2162
2163                 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2164                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2165
2166                 //TODO verify contant flag
2167
2168                 if (i + 1 < module_field_list) {
2169                         guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2170                         if (!(flags & FIELD_ATTRIBUTE_STATIC))
2171                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2172                         if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2173                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2174                 }
2175         }
2176 }
2177
2178 static void
2179 verify_field_table_full (VerifyContext *ctx)
2180 {
2181         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2182         guint32 data [MONO_FIELD_SIZE];
2183         int i;
2184         
2185         for (i = 0; i < table->rows; ++i) {
2186                 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2187
2188                 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2189                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2190         }
2191 }
2192
2193 /*bits 6,8,9,10,11,13,14,15*/
2194 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2195 static void
2196 verify_method_table (VerifyContext *ctx)
2197 {
2198         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2199         guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2200         guint32 paramlist = 1;
2201         gboolean is_ctor, is_cctor;
2202         const char *name;
2203         int i;
2204
2205         module_method_list = (guint32)-1;
2206         if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2207                 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2208                 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2209         }
2210
2211         for (i = 0; i < table->rows; ++i) {
2212                 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2213                 rva = data [MONO_METHOD_RVA];
2214                 implflags = data [MONO_METHOD_IMPLFLAGS];
2215                 flags = data [MONO_METHOD_FLAGS];
2216                 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2217                 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2218                 
2219
2220                 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2221                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2222
2223                 if (access == 0x7)
2224                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2225
2226                 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2227                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2228
2229                 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2230                 is_ctor = !strcmp (".ctor", name);
2231                 is_cctor = !strcmp (".cctor", name);
2232
2233                 if ((is_ctor || is_cctor) &&
2234                         search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2235                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2236
2237                 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2238                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2239                 
2240                 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2241                         if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2242                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2243                         if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2244                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2245                 }
2246
2247                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2248                         ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2249
2250                 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2251                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2252
2253                 //XXX no checks against cas stuff 10,11,12,13)
2254
2255                 //TODO check iface with .ctor (15,16)
2256
2257                 if (i + 1 < module_method_list) {
2258                         if (!(flags & METHOD_ATTRIBUTE_STATIC))
2259                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2260                         if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2261                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2262                         if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2263                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2264                 }
2265
2266                 //TODO check valuetype for synchronized
2267
2268                 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2269                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2270
2271                 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2272                         if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2273                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2274                         if (!(flags & METHOD_ATTRIBUTE_STATIC))
2275                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2276                 }
2277
2278                 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && 
2279                                 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2280                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2281
2282                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2283                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2284
2285                 //TODO check signature contents
2286
2287                 if (rva) {
2288                         if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2289                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2290                         if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2291                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2292                 } else {
2293                         if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2294                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2295                 }
2296
2297                 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2298                         if (rva)
2299                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2300                         if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2301                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2302                 }
2303                 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2304                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2305
2306                 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2307                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2308
2309                 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2310                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2311
2312                 if (data [MONO_METHOD_PARAMLIST] == 0)
2313                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2314
2315                 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2316                         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));
2317
2318                 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2319                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2320
2321                 paramlist = data [MONO_METHOD_PARAMLIST];
2322
2323         }
2324 }
2325
2326 static void
2327 verify_method_table_full (VerifyContext *ctx)
2328 {
2329         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2330         guint32 data [MONO_METHOD_SIZE], rva;
2331         int i;
2332
2333         for (i = 0; i < table->rows; ++i) {
2334                 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2335                 rva = data [MONO_METHOD_RVA];
2336
2337                 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2338                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2339
2340                 if (rva && !is_valid_method_header (ctx, rva))
2341                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2342         }
2343 }
2344
2345 static guint32
2346 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2347 {
2348         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2349         guint32 row = *current_method;
2350         guint32 paramlist, tmp;
2351
2352
2353         paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2354         while (row < table->rows) {
2355                 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2356                 if (tmp > paramlist) {
2357                         *current_method = row;
2358                         return tmp - paramlist;
2359                 }
2360                 ++row;
2361         }
2362
2363         /*no more methods, all params apply to the last one*/
2364         *current_method = table->rows;
2365         return (guint32)-1;
2366 }
2367
2368
2369 #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))
2370 static void
2371 verify_param_table (VerifyContext *ctx)
2372 {
2373         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2374         guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2375         gboolean first_param = TRUE;
2376         int i;
2377
2378         if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2379                 if (table->rows > 0)
2380                         ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2381                 return;
2382         }
2383         
2384         remaining_params = get_next_param_count (ctx, &current_method);
2385
2386         for (i = 0; i < table->rows; ++i) {
2387                 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2388                 flags = data [MONO_PARAM_FLAGS];
2389
2390                 if (flags & INVALID_PARAM_FLAGS_BITS)
2391                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2392
2393                 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2394                         if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2395                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2396                 } else {
2397                         if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2398                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2399                 }
2400
2401                 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)
2402                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2403
2404                 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2405                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2406
2407                 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2408                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2409
2410                 first_param = FALSE;
2411                 sequence = data [MONO_PARAM_SEQUENCE];
2412                 if (--remaining_params == 0) {
2413                         remaining_params = get_next_param_count (ctx, &current_method);
2414                         first_param = TRUE;
2415                 }
2416         }
2417 }
2418
2419 static void
2420 verify_interfaceimpl_table (VerifyContext *ctx)
2421 {
2422         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2423         guint32 data [MONO_INTERFACEIMPL_SIZE];
2424         int i;
2425
2426         for (i = 0; i < table->rows; ++i) {
2427                 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2428                 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2429                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2430
2431                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2432                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2433
2434                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2435                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2436         }
2437 }
2438
2439 static void
2440 verify_memberref_table (VerifyContext *ctx)
2441 {
2442         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2443         guint32 data [MONO_MEMBERREF_SIZE];
2444         int i;
2445
2446         for (i = 0; i < table->rows; ++i) {
2447                 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2448
2449                 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2450                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2451
2452                 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2453                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2454
2455                 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2456                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2457
2458                 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2459                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2460         }
2461 }
2462
2463
2464 static void
2465 verify_memberref_table_full (VerifyContext *ctx)
2466 {
2467         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2468         guint32 data [MONO_MEMBERREF_SIZE];
2469         int i;
2470
2471         for (i = 0; i < table->rows; ++i) {
2472                 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2473
2474                 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2475                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field  0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2476         }
2477 }
2478
2479 static void
2480 verify_constant_table (VerifyContext *ctx)
2481 {
2482         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2483         guint32 data [MONO_CONSTANT_SIZE], type;
2484         int i;
2485
2486         for (i = 0; i < table->rows; ++i) {
2487                 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2488                 type = data [MONO_CONSTANT_TYPE];
2489
2490                 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2491                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2492
2493                 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2494                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2495
2496                 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2497                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2498
2499                 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2500                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2501         }
2502 }
2503
2504 static void
2505 verify_cattr_table (VerifyContext *ctx)
2506 {
2507         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2508         guint32 data [MONO_CUSTOM_ATTR_SIZE];
2509         int i;
2510
2511         for (i = 0; i < table->rows; ++i) {
2512                 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2513
2514                 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2515                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2516
2517                 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2518                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2519
2520                 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2521                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2522         }
2523 }
2524
2525 static void
2526 verify_cattr_table_full (VerifyContext *ctx)
2527 {
2528         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2529         guint32 data [MONO_CUSTOM_ATTR_SIZE];
2530         int i;
2531
2532         for (i = 0; i < table->rows; ++i) {
2533                 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2534
2535                 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2536                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2537         }
2538 }
2539
2540 static void
2541 verify_field_marshal_table (VerifyContext *ctx)
2542 {
2543         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2544         guint32 data [MONO_FIELD_MARSHAL_SIZE];
2545         int i;
2546
2547         for (i = 0; i < table->rows; ++i) {
2548                 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2549
2550                 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2551                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2552
2553                 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2554                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2555
2556                 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2557                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2558
2559                 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2560                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2561         }
2562 }
2563
2564 static void
2565 verify_field_marshal_table_full (VerifyContext *ctx)
2566 {
2567         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2568         guint32 data [MONO_FIELD_MARSHAL_SIZE];
2569         int i;
2570
2571         for (i = 0; i < table->rows; ++i) {
2572                 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2573
2574                 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2575                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2576         }
2577 }
2578
2579 static void
2580 verify_decl_security_table (VerifyContext *ctx)
2581 {
2582         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2583         guint32 data [MONO_DECL_SECURITY_SIZE];
2584         int i;
2585
2586         for (i = 0; i < table->rows; ++i) {
2587                 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2588
2589                 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2590                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2591
2592                 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2593                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2594
2595                 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2596                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2597         }
2598 }
2599
2600 static void
2601 verify_decl_security_table_full (VerifyContext *ctx)
2602 {
2603         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2604         guint32 data [MONO_DECL_SECURITY_SIZE];
2605         int i;
2606
2607         for (i = 0; i < table->rows; ++i) {
2608                 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2609
2610                 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2611                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2612         }
2613 }
2614
2615 static void
2616 verify_class_layout_table (VerifyContext *ctx)
2617 {
2618         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2619         guint32 data [MONO_CLASS_LAYOUT_SIZE];
2620         int i;
2621
2622         for (i = 0; i < table->rows; ++i) {
2623                 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2624
2625                 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2626                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2627
2628                 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2629                 case 0:
2630                 case 1:
2631                 case 2:
2632                 case 4:
2633                 case 8:
2634                 case 16:
2635                 case 32:
2636                 case 64:
2637                 case 128:
2638                         break;
2639                 default:
2640                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2641                 }
2642         }
2643 }
2644
2645 static void
2646 verify_field_layout_table (VerifyContext *ctx)
2647 {
2648         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2649         guint32 data [MONO_FIELD_LAYOUT_SIZE];
2650         int i;
2651
2652         for (i = 0; i < table->rows; ++i) {
2653                 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2654
2655                 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2656                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2657         }
2658 }
2659
2660 static void
2661 verify_standalonesig_table (VerifyContext *ctx)
2662 {
2663         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2664         guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2665         int i;
2666
2667         for (i = 0; i < table->rows; ++i) {
2668                 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2669
2670                 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
2671                         ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2672         }
2673 }
2674
2675 static void
2676 verify_standalonesig_table_full (VerifyContext *ctx)
2677 {
2678         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2679         guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2680         int i;
2681
2682         for (i = 0; i < table->rows; ++i) {
2683                 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2684
2685                 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2686                         ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2687         }
2688 }
2689
2690 static void
2691 verify_eventmap_table (VerifyContext *ctx)
2692 {
2693         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2694         guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2695         int i;
2696
2697         for (i = 0; i < table->rows; ++i) {
2698                 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2699
2700                 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2701                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2702
2703                 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2704                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2705
2706                 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2707         }
2708 }
2709
2710 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2711 static void
2712 verify_event_table (VerifyContext *ctx)
2713 {
2714         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2715         guint32 data [MONO_EVENT_SIZE];
2716         int i;
2717
2718         for (i = 0; i < table->rows; ++i) {
2719                 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2720
2721                 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2722                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2723
2724                 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2725                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2726
2727                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2728                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2729         }
2730 }
2731
2732 static void
2733 verify_event_table_full (VerifyContext *ctx)
2734 {
2735         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2736         MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2737         guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2738         gboolean found_add, found_remove;
2739         int i, idx;
2740
2741         for (i = 0; i < table->rows; ++i) {
2742                 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2743
2744                 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2745                 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2746                 if (idx == -1)
2747                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2748
2749                 //first we move to the first row for this event
2750                 while (idx > 0) {
2751                         if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2752                                 break;
2753                         --idx;
2754                 }
2755                 //now move forward looking for AddOn and RemoveOn rows
2756                 found_add = found_remove = FALSE;
2757                 while (idx < sema_table->rows) {
2758                         mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2759                         if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2760                                 break;
2761                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2762                                 found_add = TRUE;
2763                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2764                                 found_remove = TRUE;
2765                         if (found_add && found_remove)
2766                                 break;
2767                         ++idx;
2768                 }
2769
2770                 if (!found_add)
2771                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2772                 if (!found_remove)
2773                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2774         }
2775 }
2776
2777 static void
2778 verify_propertymap_table (VerifyContext *ctx)
2779 {
2780         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2781         guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2782         int i;
2783
2784         for (i = 0; i < table->rows; ++i) {
2785                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2786
2787                 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2788                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2789
2790                 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2791                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2792
2793                 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2794         }
2795 }
2796
2797 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2798 static void
2799 verify_property_table (VerifyContext *ctx)
2800 {
2801         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2802         guint32 data [MONO_PROPERTY_SIZE];
2803         int i;
2804
2805         for (i = 0; i < table->rows; ++i) {
2806                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2807
2808                 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2809                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2810
2811                 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2812                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2813
2814                 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2815                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2816
2817                 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2818                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2819                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2820
2821         }
2822 }
2823
2824 static void
2825 verify_methodimpl_table (VerifyContext *ctx)
2826 {
2827         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2828         guint32 data [MONO_METHODIMPL_SIZE];
2829         int i;
2830
2831         for (i = 0; i < table->rows; ++i) {
2832                 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2833
2834                 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2835                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2836                         
2837                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2838                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2839                 
2840                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2841                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2842
2843                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2844                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2845                 
2846                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2847                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2848         }
2849 }
2850
2851 static void
2852 verify_moduleref_table (VerifyContext *ctx)
2853 {
2854         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2855         guint32 data [MONO_MODULEREF_SIZE];
2856         int i;
2857
2858         for (i = 0; i < table->rows; ++i) {
2859                 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2860
2861                 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2862                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2863         }
2864 }
2865
2866 static void
2867 verify_typespec_table (VerifyContext *ctx)
2868 {
2869         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2870         guint32 data [MONO_TYPESPEC_SIZE];
2871         int i;
2872
2873         for (i = 0; i < table->rows; ++i) {
2874                 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2875
2876                 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
2877                         ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2878         }
2879 }
2880
2881 static void
2882 verify_typespec_table_full (VerifyContext *ctx)
2883 {
2884         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2885         guint32 data [MONO_TYPESPEC_SIZE];
2886         int i;
2887
2888         for (i = 0; i < table->rows; ++i) {
2889                 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2890
2891                 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2892                         ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2893         }
2894 }
2895
2896 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
2897 static void
2898 verify_implmap_table (VerifyContext *ctx)
2899 {
2900         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2901         guint32 data [MONO_IMPLMAP_SIZE], cconv;
2902         int i;
2903
2904         for (i = 0; i < table->rows; ++i) {
2905                 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2906
2907                 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2908                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2909
2910                 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2911                 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2912                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2913
2914                 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2915                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2916
2917                 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2918                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2919
2920                 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2921                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2922
2923                 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2924                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2925
2926                 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
2927                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2928         }
2929 }
2930
2931 static void
2932 verify_fieldrva_table (VerifyContext *ctx)
2933 {
2934         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2935         guint32 data [MONO_FIELD_RVA_SIZE];
2936         int i;
2937
2938         for (i = 0; i < table->rows; ++i) {
2939                 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2940
2941                 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2942                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2943
2944                 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2945                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2946         }
2947 }
2948
2949 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
2950 static void
2951 verify_assembly_table (VerifyContext *ctx)
2952 {
2953         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2954         guint32 data [MONO_ASSEMBLY_SIZE], hash;
2955         int i;
2956
2957         if (table->rows > 1)
2958                 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2959
2960         for (i = 0; i < table->rows; ++i) {
2961                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2962
2963                 hash = data [MONO_ASSEMBLY_HASH_ALG];
2964                 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2965                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2966
2967                 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2968                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2969
2970                 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
2971                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2972
2973                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2974                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2975
2976                 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2977                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2978         }
2979 }
2980
2981 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2982 static void
2983 verify_assemblyref_table (VerifyContext *ctx)
2984 {
2985         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2986         guint32 data [MONO_ASSEMBLYREF_SIZE];
2987         int i;
2988
2989         for (i = 0; i < table->rows; ++i) {
2990                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2991
2992                 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2993                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2994
2995                 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
2996                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2997
2998                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2999                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3000
3001                 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3002                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3003
3004                 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3005                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3006         }
3007 }
3008
3009 #define INVALID_FILE_FLAGS_BITS ~(1)
3010 static void
3011 verify_file_table (VerifyContext *ctx)
3012 {
3013         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3014         guint32 data [MONO_FILE_SIZE];
3015         int i;
3016
3017         for (i = 0; i < table->rows; ++i) {
3018                 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3019                 
3020                 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3021                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3022
3023                 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3024                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3025
3026                 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3027                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3028         }
3029 }
3030
3031 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3032 static void
3033 verify_exportedtype_table (VerifyContext *ctx)
3034 {
3035         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3036         guint32 data [MONO_EXP_TYPE_SIZE];
3037         int i;
3038
3039         for (i = 0; i < table->rows; ++i) {
3040                 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3041                 
3042                 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3043                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3044
3045                 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3046                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3047
3048                 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3049                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3050
3051                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3052                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3053
3054                 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3055                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3056
3057                 /*nested type can't have a namespace*/
3058                 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3059                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3060         }
3061 }
3062
3063 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3064 static void
3065 verify_manifest_resource_table (VerifyContext *ctx)
3066 {
3067         MonoCLIImageInfo *iinfo = ctx->image->image_info;
3068         MonoCLIHeader *ch = &iinfo->cli_cli_header;
3069         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3070         guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3071         int i;
3072
3073         resources_size = ch->ch_resources.size;
3074
3075         for (i = 0; i < table->rows; ++i) {
3076                 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3077
3078                 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3079                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3080
3081                 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3082                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3083
3084                 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3085                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3086
3087                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3088                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3089
3090                 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3091                 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3092
3093                 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3094                         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])));
3095
3096                 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3097                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3098
3099                 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3100                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3101         }
3102 }
3103
3104 static void
3105 verify_nested_class_table (VerifyContext *ctx)
3106 {
3107         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3108         guint32 data [MONO_NESTED_CLASS_SIZE];
3109         int i;
3110
3111         for (i = 0; i < table->rows; ++i) {
3112                 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3113
3114                 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3115                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3116                 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3117                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3118                 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3119                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass  and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3120         }
3121 }
3122
3123 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3124 static void
3125 verify_generic_param_table (VerifyContext *ctx)
3126 {
3127         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3128         guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3129         int i, param_number = 0;
3130
3131         for (i = 0; i < table->rows; ++i) {
3132                 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3133
3134                 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3135                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3136
3137                 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3138                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3139
3140                 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3141                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3142
3143                 token = data [MONO_GENERICPARAM_OWNER];
3144
3145                 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3146                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3147
3148                 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3149                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3150
3151                 if (token != last_token) {
3152                         param_number = 0;
3153                         last_token = token;
3154                 }
3155
3156                 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3157                         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));
3158
3159                 ++param_number;
3160         }
3161 }
3162
3163 static void
3164 verify_method_spec_table (VerifyContext *ctx)
3165 {
3166         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3167         guint32 data [MONO_METHODSPEC_SIZE];
3168         int i;
3169
3170         for (i = 0; i < table->rows; ++i) {
3171                 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3172
3173                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3174                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3175
3176                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3177                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3178
3179                 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3180                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3181         }
3182 }
3183
3184 static void
3185 verify_method_spec_table_full (VerifyContext *ctx)
3186 {
3187         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3188         guint32 data [MONO_METHODSPEC_SIZE];
3189         int i;
3190
3191         for (i = 0; i < table->rows; ++i) {
3192                 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3193
3194                 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3195                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3196         }
3197 }
3198
3199 static void
3200 verify_generic_param_constraint_table (VerifyContext *ctx)
3201 {
3202         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3203         guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3204         int i;
3205
3206         for (i = 0; i < table->rows; ++i) {
3207                 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3208
3209                 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3210                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3211
3212                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3213                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3214
3215                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3216                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3217         }
3218 }
3219
3220 static void
3221 verify_tables_data (VerifyContext *ctx)
3222 {
3223         OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3224         guint32 size = 0, tables_offset;
3225         int i;
3226
3227         for (i = 0; i < 0x2D; ++i) {
3228                 MonoTableInfo *table = &ctx->image->tables [i];
3229                 guint32 tmp_size;
3230                 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3231                 if (tmp_size < size) {
3232                         size = 0;
3233                         break;
3234                 }
3235                 size = tmp_size;                        
3236         }
3237
3238         if (size == 0)
3239                 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3240
3241         tables_offset = ctx->image->tables_base - ctx->data;
3242         if (!bounds_check_offset (&tables_area, tables_offset, size))
3243                 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)));
3244
3245         verify_module_table (ctx);
3246         CHECK_ERROR ();
3247         verify_typeref_table (ctx);
3248         CHECK_ERROR ();
3249         verify_typedef_table (ctx);
3250         CHECK_ERROR ();
3251         verify_field_table (ctx);
3252         CHECK_ERROR ();
3253         verify_method_table (ctx);
3254         CHECK_ERROR ();
3255         verify_param_table (ctx);
3256         CHECK_ERROR ();
3257         verify_interfaceimpl_table (ctx);
3258         CHECK_ERROR ();
3259         verify_memberref_table (ctx);
3260         CHECK_ERROR ();
3261         verify_constant_table (ctx);
3262         CHECK_ERROR ();
3263         verify_cattr_table (ctx);
3264         CHECK_ERROR ();
3265         verify_field_marshal_table (ctx);
3266         CHECK_ERROR ();
3267         verify_decl_security_table (ctx);
3268         CHECK_ERROR ();
3269         verify_class_layout_table (ctx);
3270         CHECK_ERROR ();
3271         verify_field_layout_table (ctx);
3272         CHECK_ERROR ();
3273         verify_standalonesig_table (ctx);
3274         CHECK_ERROR ();
3275         verify_eventmap_table (ctx);
3276         CHECK_ERROR ();
3277         verify_event_table (ctx);
3278         CHECK_ERROR ();
3279         verify_propertymap_table (ctx);
3280         CHECK_ERROR ();
3281         verify_property_table (ctx);
3282         CHECK_ERROR ();
3283         verify_methodimpl_table (ctx);
3284         CHECK_ERROR ();
3285         verify_moduleref_table (ctx);
3286         CHECK_ERROR ();
3287         verify_typespec_table (ctx);
3288         CHECK_ERROR ();
3289         verify_implmap_table (ctx);
3290         CHECK_ERROR ();
3291         verify_fieldrva_table (ctx);
3292         CHECK_ERROR ();
3293         verify_assembly_table (ctx);
3294         CHECK_ERROR ();
3295         verify_assemblyref_table (ctx);
3296         CHECK_ERROR ();
3297         verify_file_table (ctx);
3298         CHECK_ERROR ();
3299         verify_exportedtype_table (ctx);
3300         CHECK_ERROR ();
3301         verify_manifest_resource_table (ctx);
3302         CHECK_ERROR ();
3303         verify_nested_class_table (ctx);
3304         CHECK_ERROR ();
3305         verify_generic_param_table (ctx);
3306         CHECK_ERROR ();
3307         verify_method_spec_table (ctx);
3308         CHECK_ERROR ();
3309         verify_generic_param_constraint_table (ctx);
3310 }
3311
3312 static void
3313 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
3314 {
3315         memset (ctx, 0, sizeof (VerifyContext));
3316         ctx->image = image;
3317         ctx->report_error = error_list != NULL;
3318         ctx->report_warning = FALSE; //export this setting in the API
3319         ctx->valid = 1;
3320         ctx->size = image->raw_data_len;
3321         ctx->data = image->raw_data;
3322 }
3323
3324 static gboolean
3325 cleanup_context (VerifyContext *ctx, GSList **error_list)
3326 {
3327         g_free (ctx->sections);
3328         if (error_list)
3329                 *error_list = ctx->errors;
3330         else
3331                 mono_free_verify_list (ctx->errors);
3332         return ctx->valid;      
3333 }
3334
3335 gboolean
3336 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3337 {
3338         VerifyContext ctx;
3339
3340         if (!mono_verifier_is_enabled_for_image (image))
3341                 return TRUE;
3342
3343         init_verify_context (&ctx, image, error_list);
3344         ctx.stage = STAGE_PE;
3345
3346         verify_msdos_header (&ctx);
3347         CHECK_STATE();
3348         verify_pe_header (&ctx);
3349         CHECK_STATE();
3350         verify_pe_optional_header (&ctx);
3351         CHECK_STATE();
3352         load_section_table (&ctx);
3353         CHECK_STATE();
3354         load_data_directories (&ctx);
3355         CHECK_STATE();
3356         verify_import_table (&ctx);
3357         CHECK_STATE();
3358         /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3359         verify_resources_table (&ctx);
3360
3361 cleanup:
3362         return cleanup_context (&ctx, error_list);
3363 }
3364
3365 gboolean
3366 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3367 {
3368         VerifyContext ctx;
3369
3370         if (!mono_verifier_is_enabled_for_image (image))
3371                 return TRUE;
3372
3373         init_verify_context (&ctx, image, error_list);
3374         ctx.stage = STAGE_CLI;
3375
3376         verify_cli_header (&ctx);
3377         CHECK_STATE();
3378         verify_metadata_header (&ctx);
3379         CHECK_STATE();
3380         verify_tables_schema (&ctx);
3381
3382 cleanup:
3383         return cleanup_context (&ctx, error_list);
3384 }
3385
3386
3387 /*
3388  * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3389  * Other verification checks are meant to be done lazily by the runtime. Those include:
3390  *      blob items (signatures, method headers, custom attributes, etc)
3391  *  type semantics related
3392  *  vtable related
3393  *  stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3394  * 
3395  * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3396  * operation still need more checking.
3397  */
3398 gboolean
3399 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3400 {
3401         VerifyContext ctx;
3402
3403         if (!mono_verifier_is_enabled_for_image (image))
3404                 return TRUE;
3405
3406         init_verify_context (&ctx, image, error_list);
3407         ctx.stage = STAGE_TABLES;
3408
3409         verify_tables_data (&ctx);
3410
3411         return cleanup_context (&ctx, error_list);
3412 }
3413
3414
3415 /*
3416  * Verifies all other constraints.
3417  */
3418 gboolean
3419 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3420 {
3421         VerifyContext ctx;
3422
3423         if (!mono_verifier_is_enabled_for_image (image))
3424                 return TRUE;
3425
3426         init_verify_context (&ctx, image, error_list);
3427         ctx.stage = STAGE_TABLES;
3428
3429         verify_typedef_table_full (&ctx);
3430         CHECK_STATE ();
3431         verify_field_table_full (&ctx);
3432         CHECK_STATE ();
3433         verify_method_table_full (&ctx);
3434         CHECK_STATE ();
3435         verify_memberref_table_full (&ctx);
3436         CHECK_STATE ();
3437         verify_cattr_table_full (&ctx);
3438         CHECK_STATE ();
3439         verify_field_marshal_table_full (&ctx);
3440         CHECK_STATE ();
3441         verify_decl_security_table_full (&ctx);
3442         CHECK_STATE ();
3443         verify_standalonesig_table_full (&ctx);
3444         CHECK_STATE ();
3445         verify_event_table_full (&ctx);
3446         CHECK_STATE ();
3447         verify_typespec_table_full (&ctx);
3448         CHECK_STATE ();
3449         verify_method_spec_table_full (&ctx);
3450
3451 cleanup:
3452         return cleanup_context (&ctx, error_list);
3453 }
3454
3455 gboolean
3456 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3457 {
3458         VerifyContext ctx;
3459
3460         if (!mono_verifier_is_enabled_for_image (image))
3461                 return TRUE;
3462
3463         init_verify_context (&ctx, image, error_list);
3464         ctx.stage = STAGE_TABLES;
3465
3466         is_valid_field_signature (&ctx, offset);
3467         return cleanup_context (&ctx, error_list);
3468 }
3469
3470 gboolean
3471 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3472 {
3473         VerifyContext ctx;
3474
3475         if (!mono_verifier_is_enabled_for_image (image))
3476                 return TRUE;
3477
3478         init_verify_context (&ctx, image, error_list);
3479         ctx.stage = STAGE_TABLES;
3480
3481         is_valid_method_header (&ctx, offset);
3482         return cleanup_context (&ctx, error_list);
3483 }
3484
3485 gboolean
3486 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3487 {
3488         VerifyContext ctx;
3489
3490         if (!mono_verifier_is_enabled_for_image (image))
3491                 return TRUE;
3492
3493         init_verify_context (&ctx, image, error_list);
3494         ctx.stage = STAGE_TABLES;
3495
3496         is_valid_method_signature (&ctx, offset);
3497         return cleanup_context (&ctx, error_list);
3498 }
3499
3500 gboolean
3501 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3502 {
3503         VerifyContext ctx;
3504
3505         if (!mono_verifier_is_enabled_for_image (image))
3506                 return TRUE;
3507
3508         init_verify_context (&ctx, image, error_list);
3509         ctx.stage = STAGE_TABLES;
3510
3511         is_valid_method_or_field_signature (&ctx, offset);
3512         return cleanup_context (&ctx, error_list);
3513 }
3514
3515 gboolean
3516 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3517 {
3518         VerifyContext ctx;
3519
3520         if (!mono_verifier_is_enabled_for_image (image))
3521                 return TRUE;
3522
3523         init_verify_context (&ctx, image, error_list);
3524         ctx.stage = STAGE_TABLES;
3525
3526         is_valid_standalonesig_blob (&ctx, offset);
3527         return cleanup_context (&ctx, error_list);
3528 }
3529
3530 gboolean
3531 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3532 {
3533         VerifyContext ctx;
3534
3535         if (!mono_verifier_is_enabled_for_image (image))
3536                 return TRUE;
3537
3538         init_verify_context (&ctx, image, error_list);
3539         ctx.stage = STAGE_TABLES;
3540
3541         is_valid_typespec_blob (&ctx, offset);
3542         return cleanup_context (&ctx, error_list);
3543 }
3544
3545 gboolean
3546 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3547 {
3548         VerifyContext ctx;
3549
3550         if (!mono_verifier_is_enabled_for_image (image))
3551                 return TRUE;
3552
3553         init_verify_context (&ctx, image, error_list);
3554         ctx.stage = STAGE_TABLES;
3555
3556         is_valid_methodspec_blog (&ctx, offset);
3557         return cleanup_context (&ctx, error_list);
3558 }
3559
3560 #else
3561 gboolean
3562 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3563 {
3564         return TRUE;
3565 }
3566
3567 gboolean
3568 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3569 {
3570         return TRUE;
3571 }
3572
3573 gboolean
3574 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3575 {
3576         return TRUE;
3577 }
3578
3579 gboolean
3580 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3581 {
3582         return TRUE;
3583 }
3584
3585 gboolean
3586 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3587 {
3588         return TRUE;
3589 }
3590
3591 gboolean
3592 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3593 {
3594         return TRUE;
3595 }
3596
3597 gboolean
3598 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3599 {
3600         return TRUE;
3601 }
3602
3603 gboolean
3604 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3605 {
3606         return TRUE;
3607 }
3608
3609 gboolean
3610 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3611 {
3612         return TRUE;
3613 }
3614
3615 gboolean
3616 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3617 {
3618         return TRUE;
3619 }
3620
3621 gboolean
3622 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3623 {
3624         return TRUE;
3625 }
3626
3627 #endif /* DISABLE_VERIFIER */