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