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