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