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