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