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