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_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1127 {
1128         const char *ptr = *_ptr;
1129         guint type = 0;
1130         guint32 token = 0;
1131
1132         while (TRUE) {
1133                 if (!safe_read8 (type, ptr, end))
1134                         FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1135         
1136                 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1137                         --ptr;
1138                         break;
1139                 }
1140         
1141                 if (!safe_read_cint (token, ptr, end))
1142                         FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1143         
1144                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1145                         FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1146         }
1147
1148         *_ptr = ptr;
1149         return TRUE;
1150 }
1151
1152 static gboolean
1153 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1154 {
1155         const char *ptr = *_ptr;
1156         guint8 val;
1157         guint32 size, num, i;
1158
1159         if (!safe_read8 (val, ptr, end))
1160                 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1161
1162         if (val == 0)
1163                 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1164
1165         if (!safe_read_cint (size, ptr, end))
1166                 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1167
1168         for (i = 0; i < size; ++i) {
1169                 if (!safe_read_cint (num, ptr, end))
1170                         FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1171         }
1172
1173         if (!safe_read_cint (size, ptr, end))
1174                 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1175
1176         for (i = 0; i < size; ++i) {
1177                 if (!safe_read_cint (num, ptr, end))
1178                         FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1179         }
1180
1181         *_ptr = ptr;
1182         return TRUE;
1183
1184 }
1185
1186 static gboolean
1187 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1188 {
1189         const char *ptr = *_ptr;
1190         guint8 type = 0;
1191         guint32 token = 0;
1192
1193         if (!safe_read8 (type, ptr, end))
1194                 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1195
1196         if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1197                 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1198                 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1199                 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1200                 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1201
1202         switch (type) {
1203         case MONO_TYPE_PTR:
1204                 if (!parse_custom_mods (ctx, &ptr, end))
1205                         FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1206
1207                 if (!safe_read8 (type, ptr, end))
1208                         FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1209
1210                 if (type != MONO_TYPE_VOID) {
1211                         --ptr;
1212                         if (!parse_type (ctx, &ptr, end))
1213                                 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1214                 }
1215                 break;
1216
1217         case MONO_TYPE_VALUETYPE:
1218         case MONO_TYPE_CLASS:
1219                 if (!safe_read_cint (token, ptr, end))
1220                         FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1221         
1222                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1223                         FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1224                 break;
1225
1226         case MONO_TYPE_VAR:
1227         case MONO_TYPE_MVAR:
1228                 if (!safe_read_cint (token, ptr, end))
1229                         FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1230                 break;
1231         case MONO_TYPE_ARRAY:
1232                 if (!parse_type (ctx, &ptr, end))
1233                         FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1234                 if (!parse_array_shape (ctx, &ptr, end))
1235                         FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1236                 break;
1237         }
1238         *_ptr = ptr;
1239         return TRUE;
1240 }
1241
1242 static gboolean
1243 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1244 {
1245         const char *ptr;
1246         int type = 0;
1247
1248         if (!parse_custom_mods (ctx, _ptr, end))
1249                 return FALSE;
1250
1251         ptr = *_ptr;
1252         if (!safe_read8 (type, ptr, end))
1253                 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1254
1255         if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1256                 *_ptr = ptr;
1257                 return TRUE;
1258         }
1259
1260         //it's a byref, update the cursor ptr
1261         if (type == MONO_TYPE_BYREF)
1262                 *_ptr = ptr;
1263
1264         return parse_type (ctx, _ptr, end);
1265 }
1266
1267 static gboolean
1268 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1269 {
1270         const char *ptr;
1271         int type = 0;
1272
1273         if (!parse_custom_mods (ctx, _ptr, end))
1274                 return FALSE;
1275
1276         ptr = *_ptr;
1277         if (!safe_read8 (type, ptr, end))
1278                 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1279
1280         if (type == MONO_TYPE_TYPEDBYREF) {
1281                 *_ptr = ptr;
1282                 return TRUE;
1283         }
1284
1285         //it's a byref, update the cursor ptr
1286         if (type == MONO_TYPE_BYREF)
1287                 *_ptr = ptr;
1288
1289         return parse_type (ctx, _ptr, end);
1290 }
1291
1292 static gboolean
1293 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1294 {
1295         int cconv = 0;
1296         unsigned param_count = 0, gparam_count = 0, type = 0, i;
1297         const char *ptr = *_ptr;
1298         gboolean saw_sentinel = FALSE;
1299
1300         if (!safe_read8 (cconv, ptr, end))
1301                 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1302
1303         if (cconv & 0x80)
1304                 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1305
1306         if (allow_unmanaged) {
1307                 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1308                         FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1309         } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1310                 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1311
1312         if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1313                 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1314
1315         if ((cconv & 0x10) && gparam_count == 0)
1316                 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1317
1318         if (allow_unmanaged && (cconv & 0x10))
1319                 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1320
1321         if (!safe_read_cint (param_count, ptr, end))
1322                 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1323
1324         if (!parse_return_type (ctx, &ptr, end))
1325                 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1326
1327         for (i = 0; i < param_count; ++i) {
1328                 if (allow_sentinel) {
1329                         if (!safe_read8 (type, ptr, end))
1330                                 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1331
1332                         if (type == MONO_TYPE_SENTINEL) {
1333                                 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1334                                         FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1335
1336                                 if (saw_sentinel)
1337                                         FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1338
1339                                 saw_sentinel = TRUE;
1340                         } else {
1341                                 --ptr;
1342                         }
1343                 }
1344
1345                 if (!parse_param (ctx, &ptr, end))
1346                         FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1347         }
1348
1349         *_ptr = ptr;
1350         return TRUE;
1351 }
1352
1353 static gboolean
1354 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1355 {
1356         unsigned sig = 0;
1357         unsigned param_count = 0, i;
1358         const char *ptr = *_ptr;
1359
1360         if (!safe_read8 (sig, ptr, end))
1361                 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1362
1363         if (sig != 0x08 && sig != 0x28)
1364                 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1365
1366         if (!safe_read_cint (param_count, ptr, end))
1367                 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1368
1369         if (!parse_custom_mods (ctx, &ptr, end))
1370                 return FALSE;
1371
1372         if (!parse_type (ctx, &ptr, end))
1373                 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1374
1375         for (i = 0; i < param_count; ++i) {
1376                 if (!parse_type (ctx, &ptr, end))
1377                         FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1378         }
1379
1380         *_ptr = ptr;
1381         return TRUE;
1382 }
1383
1384 static gboolean
1385 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1386 {
1387         const char *ptr = *_ptr;
1388         guint8 signature = 0;
1389
1390         if (!safe_read8 (signature, ptr, end))
1391                 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1392
1393         if (signature != 0x06)
1394                 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1395         *_ptr = ptr; 
1396
1397         if (!parse_custom_mods (ctx, _ptr, end))
1398                 return FALSE;
1399
1400         return parse_type (ctx, _ptr, end);
1401 }
1402
1403 static gboolean
1404 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1405 {
1406         unsigned sig = 0;
1407         unsigned locals_count = 0, i;
1408         const char *ptr = *_ptr;        
1409
1410         if (!safe_read8 (sig, ptr, end))
1411                 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1412
1413         if (sig != 0x07)
1414                 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1415
1416         if (!safe_read_cint (locals_count, ptr, end))
1417                 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1418
1419         if (locals_count == 0)
1420                 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1421
1422         for (i = 0; i < locals_count; ++i) {
1423                 if (!safe_read8 (sig, ptr, end))
1424                         FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1425
1426                 if (sig == MONO_TYPE_TYPEDBYREF)
1427                         continue;
1428
1429                 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1430                         if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1431                                 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1432                         if (!safe_read8 (sig, ptr, end))
1433                                 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1434                 }
1435                 --ptr;
1436                 if (!parse_type (ctx, &ptr, end))
1437                         FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1438         }
1439
1440         *_ptr = ptr;
1441         return TRUE;
1442 }
1443
1444 static gboolean
1445 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1446 {
1447         int size = 0, signature = 0;
1448         const char *ptr = NULL, *end;
1449
1450         if (!decode_signature_header (ctx, offset, &size, &ptr))
1451                 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1452         end = ptr + size;
1453
1454         if (!safe_read8 (signature, ptr, end))
1455                 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1456
1457         if (signature != 6)
1458                 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1459         --ptr;
1460
1461         return parse_field (ctx, &ptr, end);
1462 }
1463
1464 static gboolean
1465 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1466 {
1467         int size = 0;
1468         const char *ptr = NULL, *end;
1469
1470         if (!decode_signature_header (ctx, offset, &size, &ptr))
1471                 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1472         end = ptr + size;
1473
1474         return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1475 }
1476
1477 static gboolean
1478 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1479 {
1480         int size = 0;
1481         unsigned signature = 0;
1482         const char *ptr = NULL, *end;
1483
1484         if (!decode_signature_header (ctx, offset, &size, &ptr))
1485                 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1486         end = ptr + size;
1487
1488         if (!safe_read8 (signature, ptr, end))
1489                 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1490         --ptr;
1491
1492         if (signature == 0x06)
1493                 return parse_field (ctx, &ptr, end);
1494
1495         return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1496 }
1497
1498 static gboolean
1499 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1500 {
1501         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1502         //TODO do proper verification
1503         return blob.size >= 1 && blob.size - 1 >= offset;
1504 }
1505
1506 static gboolean
1507 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1508 {
1509         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1510         //TODO do proper verification
1511         return blob.size >= 1 && blob.size - 1 >= offset;
1512 }
1513
1514 static gboolean
1515 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1516 {
1517         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1518         //TODO do proper verification
1519         return blob.size >= 1 && blob.size - 1 >= offset;
1520 }
1521
1522 static gboolean
1523 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1524 {
1525         int size = 0;
1526         unsigned signature = 0;
1527         const char *ptr = NULL, *end;
1528
1529         if (!decode_signature_header (ctx, offset, &size, &ptr))
1530                 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1531         end = ptr + size;
1532
1533         if (!safe_read8 (signature, ptr, end))
1534                 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1535
1536         --ptr;
1537         if (signature == 0x07)
1538                 return parse_locals_signature (ctx, &ptr, end);
1539         return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1540 }
1541
1542 static gboolean
1543 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1544 {
1545         int size = 0;
1546         const char *ptr = NULL, *end;
1547
1548         if (!decode_signature_header (ctx, offset, &size, &ptr))
1549                 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
1550         end = ptr + size;
1551
1552         return parse_property_signature (ctx, &ptr, end);
1553 }
1554
1555 static gboolean
1556 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1557 {
1558         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1559         //TODO do proper verification
1560         return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1561 }
1562
1563 static gboolean
1564 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1565 {
1566         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1567         //TODO do proper verification
1568         return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1569 }
1570
1571 static gboolean
1572 is_valid_blob_object (VerifyContext *ctx, guint32 offset)
1573 {
1574         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1575         guint32 entry_size, bytes;
1576
1577         if (blob.size < offset) {
1578                 printf ("1\n");
1579                 return FALSE;
1580         }
1581
1582         if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1583                 return FALSE;
1584
1585         if (offset + entry_size + bytes < offset)
1586                 return FALSE;
1587
1588         return blob.size >= offset + entry_size + bytes;
1589 }
1590
1591 static gboolean
1592 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1593 {
1594         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1595         guint32 size, entry_size, bytes;
1596
1597         if (blob.size < offset) {
1598                 printf ("1\n");
1599                 return FALSE;
1600         }
1601
1602         
1603         if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1604                 return FALSE;
1605
1606         if (type == MONO_TYPE_STRING) {
1607                 //String is encoded as: compressed_int:len len *chars
1608
1609                 offset += bytes;
1610                 if (offset > offset + entry_size * 2) //overflow
1611                         return FALSE;
1612                 offset += offset + entry_size * 2;
1613                 return  offset <= blob.size;
1614         }
1615
1616         switch (type) {
1617         case MONO_TYPE_BOOLEAN:
1618         case MONO_TYPE_I1:
1619         case MONO_TYPE_U1:
1620                 size = 1;
1621                 break;
1622         case MONO_TYPE_CHAR:
1623         case MONO_TYPE_I2:
1624         case MONO_TYPE_U2:
1625                 size = 2;
1626                 break;
1627         case MONO_TYPE_I4:
1628         case MONO_TYPE_U4:
1629         case MONO_TYPE_R4:
1630         case MONO_TYPE_CLASS:
1631                 size = 4;
1632                 break;
1633
1634         case MONO_TYPE_I8:
1635         case MONO_TYPE_U8:
1636         case MONO_TYPE_R8:
1637                 size = 8;
1638                 break;
1639         default:
1640                 g_assert_not_reached ();
1641         }
1642
1643         if (size != entry_size)
1644                 return FALSE;
1645         offset += bytes;
1646
1647         if(offset > offset + size) //overflow
1648                 return FALSE;
1649
1650         if (offset + size > blob.size)
1651                 return FALSE;
1652
1653         if (type == MONO_TYPE_CLASS && read32 (ctx->data + offset))
1654                 return FALSE;
1655         return TRUE;
1656 }
1657
1658 static gboolean
1659 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1660 {
1661         //TODO do proper method header validation
1662         return mono_cli_rva_image_map (ctx->image, rva) != INVALID_ADDRESS;
1663 }
1664
1665 static void
1666 verify_module_table (VerifyContext *ctx)
1667 {
1668         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1669         guint32 data [MONO_MODULE_SIZE];
1670
1671         if (table->rows != 1)
1672                 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1673
1674         mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1675
1676         if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1677                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1678
1679         if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1680                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1681
1682         if (data [MONO_MODULE_ENC] != 0)
1683                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1684
1685         if (data [MONO_MODULE_ENCBASE] != 0)
1686                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1687 }
1688
1689 static void
1690 verify_typeref_table (VerifyContext *ctx)
1691 {
1692         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1693         guint32 data [MONO_TYPEREF_SIZE];
1694         int i;
1695
1696         for (i = 0; i < table->rows; ++i) {
1697                 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1698                 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1699                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1700                 
1701                 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1702                         ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1703
1704                 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1705                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1706
1707                 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1708                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
1709         }
1710 }
1711
1712 /*bits 9,11,14,15,19,21,24-31 */
1713 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
1714 static void
1715 verify_typedef_table (VerifyContext *ctx)
1716 {
1717         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1718         guint32 data [MONO_TYPEDEF_SIZE];
1719         guint32 fieldlist = 1, methodlist = 1;
1720         int i;
1721
1722         if (table->rows == 0)
1723                 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
1724
1725         for (i = 0; i < table->rows; ++i) {
1726                 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
1727                 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
1728                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
1729
1730                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
1731                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
1732
1733                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
1734                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1735
1736                 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
1737                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1738
1739                 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
1740                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
1741
1742                 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1743                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
1744
1745                 if (i == 0) {
1746                         if (data [MONO_TYPEDEF_EXTENDS] != 0)
1747                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
1748                 } else {
1749                         if (typedef_is_system_object (ctx, data) && data [MONO_TYPEDEF_EXTENDS] != 0)
1750                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
1751         
1752                         if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
1753                                 if (data [MONO_TYPEDEF_EXTENDS])
1754                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
1755                                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
1756                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
1757                         } else {
1758                                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1759                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
1760         
1761                                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS])) 
1762                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
1763                         }
1764                 }
1765
1766                 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
1767                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
1768
1769                 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
1770                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
1771
1772                 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
1773                         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));
1774
1775                 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
1776                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
1777
1778                 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
1779                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
1780
1781                 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
1782                         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));
1783
1784
1785                 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
1786                 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
1787         }
1788 }
1789
1790 /*bits 3,11,14 */
1791 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
1792 static void
1793 verify_field_table (VerifyContext *ctx)
1794 {
1795         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
1796         guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
1797         int i;
1798
1799         module_field_list = (guint32)-1;
1800         if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1801                 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1802                 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
1803         }
1804         
1805         for (i = 0; i < table->rows; ++i) {
1806                 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
1807                 flags = data [MONO_FIELD_FLAGS];
1808
1809                 if (flags & INVALID_FIELD_FLAG_BITS)
1810                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
1811
1812                 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)         
1813                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
1814
1815                 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
1816                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
1817
1818                 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
1819                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
1820
1821                 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
1822                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
1823
1824                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
1825                                 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
1826                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
1827
1828                 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
1829                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1830                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1831
1832                 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
1833                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1834                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
1835
1836                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
1837                                 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
1838                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1839
1840                 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
1841                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
1842
1843                 //TODO verify contant flag
1844                 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
1845                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
1846
1847                 if (i + 1 < module_field_list) {
1848                         guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
1849                         if (!(flags & FIELD_ATTRIBUTE_STATIC))
1850                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
1851                         if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
1852                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
1853                 }
1854         }
1855 }
1856
1857 /*bits 6,8,9,10,11,13,14,15*/
1858 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
1859 static void
1860 verify_method_table (VerifyContext *ctx)
1861 {
1862         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1863         guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
1864         guint32 paramlist = 1;
1865         gboolean is_ctor, is_cctor;
1866         const char *name;
1867         int i;
1868
1869         module_method_list = (guint32)-1;
1870         if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1871                 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1872                 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
1873         }
1874
1875         for (i = 0; i < table->rows; ++i) {
1876                 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
1877                 rva = data [MONO_METHOD_RVA];
1878                 implflags = data [MONO_METHOD_IMPLFLAGS];
1879                 flags = data [MONO_METHOD_FLAGS];
1880                 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
1881                 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
1882                 
1883
1884                 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
1885                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
1886
1887                 if (access == 0x7)
1888                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
1889
1890                 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
1891                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
1892
1893                 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
1894                 is_ctor = !strcmp (".ctor", name);
1895                 is_cctor = !strcmp (".cctor", name);
1896
1897                 if ((is_ctor || is_cctor) &&
1898                         search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
1899                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
1900
1901                 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
1902                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
1903                 
1904                 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
1905                         if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1906                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
1907                         if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
1908                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
1909                 }
1910
1911                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
1912                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
1913
1914                 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
1915                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
1916
1917                 //XXX no checks against cas stuff 10,11,12,13)
1918
1919                 //TODO check iface with .ctor (15,16)
1920
1921                 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
1922                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
1923
1924                 if (i + 1 < module_method_list) {
1925                         if (!(flags & METHOD_ATTRIBUTE_STATIC))
1926                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
1927                         if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
1928                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
1929                         if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
1930                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
1931                 }
1932
1933                 //TODO check valuetype for synchronized
1934
1935                 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
1936                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
1937
1938                 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
1939                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
1940
1941                 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && 
1942                                 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1943                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
1944
1945                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
1946                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
1947
1948                 //TODO check signature contents
1949
1950                 if (rva) {
1951                         if (flags & METHOD_ATTRIBUTE_ABSTRACT)
1952                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
1953                         if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
1954                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
1955                         if (!is_valid_method_header (ctx, rva))
1956                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
1957                 } else {
1958                         if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1959                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
1960                 }
1961
1962                 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
1963                         if (rva)
1964                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
1965                         if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
1966                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
1967                 }
1968                 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
1969                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
1970
1971                 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
1972                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
1973
1974                 if (data [MONO_METHOD_PARAMLIST] == 0)
1975                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
1976
1977                 if (data [MONO_METHOD_PARAMLIST] < paramlist)
1978                         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));
1979
1980                 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
1981                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
1982
1983                 paramlist = data [MONO_METHOD_PARAMLIST];
1984
1985         }
1986 }
1987
1988 static guint32
1989 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
1990 {
1991         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1992         guint32 row = *current_method;
1993         guint32 paramlist, tmp;
1994
1995
1996         paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
1997         while (row < table->rows) {
1998                 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
1999                 if (tmp > paramlist) {
2000                         *current_method = row;
2001                         return tmp - paramlist;
2002                 }
2003                 ++row;
2004         }
2005
2006         /*no more methods, all params apply to the last one*/
2007         *current_method = table->rows;
2008         return (guint32)-1;
2009 }
2010
2011
2012 #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))
2013 static void
2014 verify_param_table (VerifyContext *ctx)
2015 {
2016         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2017         guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2018         gboolean first_param = TRUE;
2019         int i;
2020
2021         remaining_params = get_next_param_count (ctx, &current_method);
2022
2023         for (i = 0; i < table->rows; ++i) {
2024                 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2025                 flags = data [MONO_PARAM_FLAGS];
2026
2027                 if (flags & INVALID_PARAM_FLAGS_BITS)
2028                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2029
2030                 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2031                         if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2032                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2033                 } else {
2034                         if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2035                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2036                 }
2037
2038                 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)
2039                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2040
2041                 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2042                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2043
2044                 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2045                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2046
2047                 first_param = FALSE;
2048                 sequence = data [MONO_PARAM_SEQUENCE];
2049                 if (--remaining_params == 0) {
2050                         remaining_params = get_next_param_count (ctx, &current_method);
2051                         first_param = TRUE;
2052                 }
2053         }
2054 }
2055
2056 static void
2057 verify_interfaceimpl_table (VerifyContext *ctx)
2058 {
2059         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2060         guint32 data [MONO_INTERFACEIMPL_SIZE];
2061         int i;
2062
2063         for (i = 0; i < table->rows; ++i) {
2064                 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2065                 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2066                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2067
2068                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2069                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2070
2071                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2072                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2073         }
2074 }
2075
2076 static void
2077 verify_memberref_table (VerifyContext *ctx)
2078 {
2079         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2080         guint32 data [MONO_MEMBERREF_SIZE];
2081         int i;
2082
2083         for (i = 0; i < table->rows; ++i) {
2084                 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2085
2086                 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2087                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2088
2089                 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2090                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2091
2092                 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2093                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2094
2095                 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2096                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field  0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2097         }
2098 }
2099
2100 static void
2101 verify_constant_table (VerifyContext *ctx)
2102 {
2103         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2104         guint32 data [MONO_CONSTANT_SIZE], type;
2105         int i;
2106
2107         for (i = 0; i < table->rows; ++i) {
2108                 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2109                 type = data [MONO_CONSTANT_TYPE];
2110
2111                 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2112                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2113
2114                 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2115                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2116
2117                 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2118                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2119
2120                 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2121                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2122         }
2123 }
2124
2125 static void
2126 verify_cattr_table (VerifyContext *ctx)
2127 {
2128         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2129         guint32 data [MONO_CUSTOM_ATTR_SIZE];
2130         int i;
2131
2132         for (i = 0; i < table->rows; ++i) {
2133                 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2134
2135                 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2136                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2137
2138                 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2139                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2140
2141                 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2142                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2143                         
2144         }
2145 }
2146
2147 static void
2148 verify_field_marshal_table (VerifyContext *ctx)
2149 {
2150         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2151         guint32 data [MONO_FIELD_MARSHAL_SIZE];
2152         int i;
2153
2154         for (i = 0; i < table->rows; ++i) {
2155                 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2156
2157                 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2158                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2159
2160                 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2161                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2162
2163                 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2164                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2165
2166                 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2167                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2168                         
2169         }
2170 }
2171
2172 static void
2173 verify_decl_security_table (VerifyContext *ctx)
2174 {
2175         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2176         guint32 data [MONO_DECL_SECURITY_SIZE];
2177         int i;
2178
2179         for (i = 0; i < table->rows; ++i) {
2180                 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2181
2182                 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2183                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2184
2185                 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2186                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2187
2188                 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2189                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2190
2191                 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2192                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2193
2194         }
2195 }
2196
2197 static void
2198 verify_class_layout_table (VerifyContext *ctx)
2199 {
2200         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2201         guint32 data [MONO_CLASS_LAYOUT_SIZE];
2202         int i;
2203
2204         for (i = 0; i < table->rows; ++i) {
2205                 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2206
2207                 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2208                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2209
2210                 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2211                 case 0:
2212                 case 1:
2213                 case 2:
2214                 case 4:
2215                 case 8:
2216                 case 16:
2217                 case 32:
2218                 case 64:
2219                 case 128:
2220                         break;
2221                 default:
2222                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2223                 }
2224         }
2225 }
2226
2227 static void
2228 verify_field_layout_table (VerifyContext *ctx)
2229 {
2230         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2231         guint32 data [MONO_FIELD_LAYOUT_SIZE];
2232         int i;
2233
2234         for (i = 0; i < table->rows; ++i) {
2235                 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2236
2237                 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2238                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2239         }
2240 }
2241
2242 static void
2243 verify_standalonesig_table (VerifyContext *ctx)
2244 {
2245         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2246         guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2247         int i;
2248
2249         for (i = 0; i < table->rows; ++i) {
2250                 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2251
2252                 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2253                         ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2254         }
2255 }
2256
2257 static void
2258 verify_eventmap_table (VerifyContext *ctx)
2259 {
2260         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2261         guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2262         int i;
2263
2264         for (i = 0; i < table->rows; ++i) {
2265                 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2266
2267                 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2268                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2269
2270                 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2271                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2272
2273                 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2274         }
2275 }
2276
2277 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2278 static void
2279 verify_event_table (VerifyContext *ctx)
2280 {
2281         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2282         MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2283         guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2284         gboolean found_add, found_remove;
2285         int i, idx;
2286
2287         for (i = 0; i < table->rows; ++i) {
2288                 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2289
2290                 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2291                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2292
2293                 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2294                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2295
2296                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2297                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2298
2299                 //check for Add and Remove
2300                 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2301                 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2302                 if (idx == -1)
2303                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2304
2305                 //first we move to the first row for this event
2306                 while (idx > 0) {
2307                         if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2308                                 break;
2309                         --idx;
2310                 }
2311                 //now move forward looking for AddOn and RemoveOn rows
2312                 found_add = found_remove = FALSE;
2313                 while (idx < sema_table->rows) {
2314                         mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2315                         if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2316                                 break;
2317                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2318                                 found_add = TRUE;
2319                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2320                                 found_remove = TRUE;
2321                         if (found_add && found_remove)
2322                                 break;
2323                         ++idx;
2324                 }
2325
2326                 if (!found_add)
2327                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2328                 if (!found_remove)
2329                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2330         }
2331 }
2332
2333 static void
2334 verify_propertymap_table (VerifyContext *ctx)
2335 {
2336         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2337         guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2338         int i;
2339
2340         for (i = 0; i < table->rows; ++i) {
2341                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2342
2343                 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2344                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2345
2346                 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2347                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2348
2349                 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2350         }
2351 }
2352
2353 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2354 static void
2355 verify_property_table (VerifyContext *ctx)
2356 {
2357         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2358         guint32 data [MONO_PROPERTY_SIZE];
2359         int i;
2360
2361         for (i = 0; i < table->rows; ++i) {
2362                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2363
2364                 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2365                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2366
2367                 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2368                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2369
2370                 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2371                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2372
2373                 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2374                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2375                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2376
2377         }
2378 }
2379
2380 static void
2381 verify_methodimpl_table (VerifyContext *ctx)
2382 {
2383         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2384         guint32 data [MONO_METHODIMPL_SIZE];
2385         int i;
2386
2387         for (i = 0; i < table->rows; ++i) {
2388                 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2389
2390                 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2391                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2392                         
2393                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2394                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2395                 
2396                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2397                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2398
2399                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2400                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2401                 
2402                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2403                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2404         }
2405 }
2406
2407 static void
2408 verify_moduleref_table (VerifyContext *ctx)
2409 {
2410         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2411         guint32 data [MONO_MODULEREF_SIZE];
2412         int i;
2413
2414         for (i = 0; i < table->rows; ++i) {
2415                 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2416
2417                 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2418                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2419         }
2420 }
2421
2422 static void
2423 verify_typespec_table (VerifyContext *ctx)
2424 {
2425         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2426         guint32 data [MONO_TYPESPEC_SIZE];
2427         int i;
2428
2429         for (i = 0; i < table->rows; ++i) {
2430                 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2431
2432                 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2433                         ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2434         }
2435 }
2436
2437 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10))
2438 static void
2439 verify_implmap_table (VerifyContext *ctx)
2440 {
2441         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2442         guint32 data [MONO_IMPLMAP_SIZE], cconv;
2443         int i;
2444
2445         for (i = 0; i < table->rows; ++i) {
2446                 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2447
2448                 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2449                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2450
2451                 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2452                 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2453                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2454
2455                 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2456                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2457
2458                 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2459                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2460
2461                 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2462                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2463
2464                 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2465                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2466
2467                 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULE].rows + 1)
2468                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2469         }
2470 }
2471
2472 static void
2473 verify_fieldrva_table (VerifyContext *ctx)
2474 {
2475         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2476         guint32 data [MONO_FIELD_RVA_SIZE];
2477         int i;
2478
2479         for (i = 0; i < table->rows; ++i) {
2480                 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2481
2482                 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2483                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2484
2485                 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2486                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2487         }
2488 }
2489
2490 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
2491 static void
2492 verify_assembly_table (VerifyContext *ctx)
2493 {
2494         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2495         guint32 data [MONO_ASSEMBLY_SIZE], hash;
2496         int i;
2497
2498         if (table->rows > 1)
2499                 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2500
2501         for (i = 0; i < table->rows; ++i) {
2502                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2503
2504                 hash = data [MONO_ASSEMBLY_HASH_ALG];
2505                 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2506                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2507
2508                 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2509                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2510
2511                 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY]))
2512                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2513
2514                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2515                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2516
2517                 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2518                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2519         }
2520 }
2521
2522 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2523 static void
2524 verify_assemblyref_table (VerifyContext *ctx)
2525 {
2526         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2527         guint32 data [MONO_ASSEMBLYREF_SIZE];
2528         int i;
2529
2530         for (i = 0; i < table->rows; ++i) {
2531                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2532
2533                 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2534                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2535
2536                 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY]))
2537                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2538
2539                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2540                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
2541
2542                 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
2543                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
2544
2545                 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE]))
2546                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
2547         }
2548 }
2549
2550 #define INVALID_FILE_FLAGS_BITS ~(1)
2551 static void
2552 verify_file_table (VerifyContext *ctx)
2553 {
2554         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
2555         guint32 data [MONO_FILE_SIZE];
2556         int i;
2557
2558         for (i = 0; i < table->rows; ++i) {
2559                 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
2560                 
2561                 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
2562                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
2563
2564                 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
2565                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
2566
2567                 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE]))
2568                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
2569         }
2570 }
2571
2572 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
2573 static void
2574 verify_exportedtype_table (VerifyContext *ctx)
2575 {
2576         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
2577         guint32 data [MONO_EXP_TYPE_SIZE];
2578         int i;
2579
2580         for (i = 0; i < table->rows; ++i) {
2581                 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
2582                 
2583                 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
2584                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
2585
2586                 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
2587                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
2588
2589                 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
2590                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
2591
2592                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2593                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
2594
2595                 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2596                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
2597
2598                 /*nested type can't have a namespace*/
2599                 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
2600                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
2601         }
2602 }
2603
2604 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
2605 static void
2606 verify_manifest_resource_table (VerifyContext *ctx)
2607 {
2608         MonoCLIImageInfo *iinfo = ctx->image->image_info;
2609         MonoCLIHeader *ch = &iinfo->cli_cli_header;
2610         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
2611         guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
2612         int i;
2613
2614         resources_size = ch->ch_resources.size;
2615
2616         for (i = 0; i < table->rows; ++i) {
2617                 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
2618
2619                 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
2620                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
2621
2622                 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
2623                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
2624
2625                 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
2626                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
2627
2628                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
2629                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
2630
2631                 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2632                 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2633
2634                 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
2635                         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])));
2636
2637                 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
2638                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
2639
2640                 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
2641                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
2642         }
2643 }
2644
2645 static void
2646 verify_nested_class_table (VerifyContext *ctx)
2647 {
2648         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
2649         guint32 data [MONO_NESTED_CLASS_SIZE];
2650         int i;
2651
2652         for (i = 0; i < table->rows; ++i) {
2653                 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
2654
2655                 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2656                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
2657                 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2658                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2659                 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
2660                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass  and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2661         }
2662 }
2663
2664 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
2665 static void
2666 verify_generic_param_table (VerifyContext *ctx)
2667 {
2668         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
2669         guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
2670         int i, param_number = 0;
2671
2672         for (i = 0; i < table->rows; ++i) {
2673                 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
2674
2675                 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
2676                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
2677
2678                 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
2679                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
2680
2681                 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
2682                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
2683
2684                 token = data [MONO_GENERICPARAM_OWNER];
2685
2686                 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
2687                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
2688
2689                 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
2690                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
2691
2692                 if (token != last_token) {
2693                         param_number = 0;
2694                         last_token = token;
2695                 }
2696
2697                 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
2698                         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));
2699
2700                 ++param_number;
2701         }
2702 }
2703
2704 static void
2705 verify_method_spec_table (VerifyContext *ctx)
2706 {
2707         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
2708         guint32 data [MONO_METHODSPEC_SIZE];
2709         int i;
2710
2711         for (i = 0; i < table->rows; ++i) {
2712                 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
2713
2714                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2715                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
2716
2717                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2718                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
2719
2720                 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
2721                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
2722         }
2723 }
2724
2725 static void
2726 verify_generic_param_constraint_table (VerifyContext *ctx)
2727 {
2728         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
2729         guint32 data [MONO_GENPARCONSTRAINT_SIZE];
2730         int i;
2731
2732         for (i = 0; i < table->rows; ++i) {
2733                 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
2734
2735                 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
2736                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
2737
2738                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2739                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
2740
2741                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2742                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
2743         }
2744 }
2745
2746 static void
2747 verify_tables_data (VerifyContext *ctx)
2748 {
2749         OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
2750         guint32 size = 0, tables_offset;
2751         int i;
2752
2753         for (i = 0; i < 0x2D; ++i) {
2754                 MonoTableInfo *table = &ctx->image->tables [i];
2755                 guint32 tmp_size;
2756                 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
2757                 if (tmp_size < size) {
2758                         size = 0;
2759                         break;
2760                 }
2761                 size = tmp_size;                        
2762         }
2763
2764         if (size == 0)
2765                 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
2766
2767         tables_offset = ctx->image->tables_base - ctx->data;
2768         if (!bounds_check_offset (&tables_area, tables_offset, size))
2769                 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)));
2770
2771         verify_module_table (ctx);
2772         CHECK_ERROR ();
2773         verify_typeref_table (ctx);
2774         CHECK_ERROR ();
2775         verify_typedef_table (ctx);
2776         CHECK_ERROR ();
2777         verify_field_table (ctx);
2778         CHECK_ERROR ();
2779         verify_method_table (ctx);
2780         CHECK_ERROR ();
2781         verify_param_table (ctx);
2782         CHECK_ERROR ();
2783         verify_interfaceimpl_table (ctx);
2784         CHECK_ERROR ();
2785         verify_memberref_table (ctx);
2786         CHECK_ERROR ();
2787         verify_constant_table (ctx);
2788         CHECK_ERROR ();
2789         verify_cattr_table (ctx);
2790         CHECK_ERROR ();
2791         verify_field_marshal_table (ctx);
2792         CHECK_ERROR ();
2793         verify_decl_security_table (ctx);
2794         CHECK_ERROR ();
2795         verify_class_layout_table (ctx);
2796         CHECK_ERROR ();
2797         verify_field_layout_table (ctx);
2798         CHECK_ERROR ();
2799         verify_standalonesig_table (ctx);
2800         CHECK_ERROR ();
2801         verify_eventmap_table (ctx);
2802         CHECK_ERROR ();
2803         verify_event_table (ctx);
2804         CHECK_ERROR ();
2805         verify_propertymap_table (ctx);
2806         CHECK_ERROR ();
2807         verify_property_table (ctx);
2808         CHECK_ERROR ();
2809         verify_methodimpl_table (ctx);
2810         CHECK_ERROR ();
2811         verify_moduleref_table (ctx);
2812         CHECK_ERROR ();
2813         verify_typespec_table (ctx);
2814         CHECK_ERROR ();
2815         verify_implmap_table (ctx);
2816         CHECK_ERROR ();
2817         verify_fieldrva_table (ctx);
2818         CHECK_ERROR ();
2819         verify_assembly_table (ctx);
2820         CHECK_ERROR ();
2821         verify_assemblyref_table (ctx);
2822         CHECK_ERROR ();
2823         verify_file_table (ctx);
2824         CHECK_ERROR ();
2825         verify_exportedtype_table (ctx);
2826         CHECK_ERROR ();
2827         verify_manifest_resource_table (ctx);
2828         CHECK_ERROR ();
2829         verify_nested_class_table (ctx);
2830         CHECK_ERROR ();
2831         verify_generic_param_table (ctx);
2832         CHECK_ERROR ();
2833         verify_method_spec_table (ctx);
2834         CHECK_ERROR ();
2835         verify_generic_param_constraint_table (ctx);
2836 }
2837
2838 static gboolean
2839 mono_verifier_is_corlib (MonoImage *image)
2840 {
2841         gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ? 
2842                         TRUE : mono_security_core_clr_is_platform_image (image);
2843
2844         return trusted_location && !strcmp ("mscorlib.dll", image->name);
2845 }
2846
2847 static void
2848 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
2849 {
2850         memset (ctx, 0, sizeof (VerifyContext));
2851         ctx->image = image;
2852         ctx->report_error = error_list != NULL;
2853         ctx->valid = 1;
2854         ctx->size = image->raw_data_len;
2855         ctx->data = image->raw_data;
2856         ctx->is_corlib = mono_verifier_is_corlib (image);       
2857 }
2858
2859 static gboolean
2860 cleanup_context (VerifyContext *ctx, GSList **error_list)
2861 {
2862         g_free (ctx->sections);
2863         if (error_list)
2864                 *error_list = ctx->errors;
2865         else
2866                 mono_free_verify_list (ctx->errors);
2867         return ctx->valid;      
2868 }
2869
2870 gboolean
2871 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2872 {
2873         VerifyContext ctx;
2874
2875         if (!mono_verifier_is_enabled_for_image (image))
2876                 return TRUE;
2877
2878         init_verify_context (&ctx, image, error_list);
2879         ctx.stage = STAGE_PE;
2880
2881         verify_msdos_header (&ctx);
2882         CHECK_STATE();
2883         verify_pe_header (&ctx);
2884         CHECK_STATE();
2885         verify_pe_optional_header (&ctx);
2886         CHECK_STATE();
2887         load_section_table (&ctx);
2888         CHECK_STATE();
2889         load_data_directories (&ctx);
2890         CHECK_STATE();
2891         verify_import_table (&ctx);
2892         CHECK_STATE();
2893         /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
2894         verify_resources_table (&ctx);
2895
2896 cleanup:
2897         return cleanup_context (&ctx, error_list);
2898 }
2899
2900 gboolean
2901 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2902 {
2903         VerifyContext ctx;
2904
2905         if (!mono_verifier_is_enabled_for_image (image))
2906                 return TRUE;
2907
2908         init_verify_context (&ctx, image, error_list);
2909         ctx.stage = STAGE_CLI;
2910
2911         verify_cli_header (&ctx);
2912         CHECK_STATE();
2913         verify_metadata_header (&ctx);
2914         CHECK_STATE();
2915         verify_tables_schema (&ctx);
2916
2917 cleanup:
2918         return cleanup_context (&ctx, error_list);
2919 }
2920
2921 gboolean
2922 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2923 {
2924         VerifyContext ctx;
2925
2926         if (!mono_verifier_is_enabled_for_image (image))
2927                 return TRUE;
2928
2929         init_verify_context (&ctx, image, error_list);
2930         ctx.stage = STAGE_TABLES;
2931
2932         verify_tables_data (&ctx);
2933
2934         return cleanup_context (&ctx, error_list);
2935 }
2936 #else
2937 gboolean
2938 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2939 {
2940         return TRUE;
2941 }
2942
2943 gboolean
2944 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2945 {
2946         return TRUE;
2947 }
2948
2949 gboolean
2950 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2951 {
2952         return TRUE;
2953 }
2954 #endif /* DISABLE_VERIFIER */