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