2009-04-28 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
10 #include <mono/metadata/object-internals.h>
11 #include <mono/metadata/verify.h>
12 #include <mono/metadata/verify-internals.h>
13 #include <mono/metadata/opcodes.h>
14 #include <mono/metadata/tabledefs.h>
15 #include <mono/metadata/reflection.h>
16 #include <mono/metadata/debug-helpers.h>
17 #include <mono/metadata/mono-endian.h>
18 #include <mono/metadata/metadata.h>
19 #include <mono/metadata/metadata-internals.h>
20 #include <mono/metadata/class-internals.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/security-manager.h>
23 #include <mono/metadata/security-core-clr.h>
24 #include <mono/metadata/cil-coff.h>
25 #include <mono/utils/strenc.h>
26 #include <string.h>
27 #include <signal.h>
28 #include <ctype.h>
29
30 /*
31  TODO add fail fast mode
32  TODO add PE32+ support
33  TODO verify the entry point RVA and content.
34  TODO load_section_table and load_data_directories must take PE32+ into account
35  TODO add section relocation support
36  TODO verify the relocation table, since we really don't use, no need so far.
37  TODO do full PECOFF resources verification 
38  TODO verify in the CLI header entry point and resources
39  TODO implement null token typeref validation  
40  TODO verify table wide invariants for typedef (sorting and uniqueness)
41  TODO implement proper authenticode data directory validation
42  TODO verify properties that require multiple tables to be valid 
43  FIXME use subtraction based bounds checking to avoid overflows
44  FIXME get rid of metadata_streams and other fields from VerifyContext
45 */
46
47 #ifdef MONO_VERIFIER_DEBUG
48 #define VERIFIER_DEBUG(code) do { code; } while (0)
49 #else
50 #define VERIFIER_DEBUG(code)
51 #endif
52
53 #define INVALID_OFFSET ((guint32)-1)
54 #define INVALID_ADDRESS 0xffffffff
55
56 enum {
57         STAGE_PE,
58         STAGE_CLI,
59         STAGE_TABLES
60 };
61
62 enum {
63         IMPORT_TABLE_IDX = 1, 
64         RESOURCE_TABLE_IDX = 2,
65         CERTIFICATE_TABLE_IDX = 4,
66         RELOCATION_TABLE_IDX = 5,
67         IAT_IDX = 12,
68         CLI_HEADER_IDX = 14,
69 };
70
71 enum {
72         STRINGS_STREAM,
73         USER_STRINGS_STREAM,
74         BLOB_STREAM,
75         GUID_STREAM,
76         TILDE_STREAM
77 };
78
79
80 #define INVALID_TABLE (0xFF)
81 /*format: number of bits, number of tables, tables{n. tables} */
82 const static unsigned char coded_index_desc[] = {
83 #define TYPEDEF_OR_REF_DESC (0)
84         2, /*bits*/
85         3, /*tables*/
86         MONO_TABLE_TYPEDEF,
87         MONO_TABLE_TYPEREF,
88         MONO_TABLE_TYPESPEC,
89
90 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
91         2, /*bits*/
92         3, /*tables*/
93         MONO_TABLE_FIELD,
94         MONO_TABLE_PARAM,
95         MONO_TABLE_PROPERTY,
96
97 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
98         5, /*bits*/
99         19, /*tables*/
100         MONO_TABLE_METHOD,
101         MONO_TABLE_FIELD,
102         MONO_TABLE_TYPEREF,
103         MONO_TABLE_TYPEDEF,
104         MONO_TABLE_PARAM,
105         MONO_TABLE_INTERFACEIMPL,
106         MONO_TABLE_MEMBERREF,
107         MONO_TABLE_MODULE,
108         MONO_TABLE_DECLSECURITY,
109         MONO_TABLE_PROPERTY, 
110         MONO_TABLE_EVENT,
111         MONO_TABLE_STANDALONESIG,
112         MONO_TABLE_MODULEREF,
113         MONO_TABLE_TYPESPEC,
114         MONO_TABLE_ASSEMBLY,
115         MONO_TABLE_ASSEMBLYREF,
116         MONO_TABLE_FILE,
117         MONO_TABLE_EXPORTEDTYPE,
118         MONO_TABLE_MANIFESTRESOURCE,
119
120 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 21)
121         1, /*bits*/
122         2, /*tables*/
123         MONO_TABLE_FIELD,
124         MONO_TABLE_PARAM,
125
126 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
127         2, /*bits*/
128         3, /*tables*/
129         MONO_TABLE_TYPEDEF,
130         MONO_TABLE_METHOD,
131         MONO_TABLE_ASSEMBLY,
132
133 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
134         3, /*bits*/
135         5, /*tables*/
136         MONO_TABLE_TYPEDEF,
137         MONO_TABLE_TYPEREF,
138         MONO_TABLE_MODULE,
139         MONO_TABLE_METHOD,
140         MONO_TABLE_TYPESPEC,
141
142 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
143         1, /*bits*/
144         2, /*tables*/
145         MONO_TABLE_EVENT,
146         MONO_TABLE_PROPERTY,
147
148 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
149         1, /*bits*/
150         2, /*tables*/
151         MONO_TABLE_METHOD,
152         MONO_TABLE_MEMBERREF,
153
154 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
155         1, /*bits*/
156         2, /*tables*/
157         MONO_TABLE_FIELD,
158         MONO_TABLE_METHOD,
159
160 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
161         2, /*bits*/
162         3, /*tables*/
163         MONO_TABLE_FILE,
164         MONO_TABLE_ASSEMBLYREF,
165         MONO_TABLE_EXPORTEDTYPE,
166
167 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
168         3, /*bits*/
169         5, /*tables*/
170         INVALID_TABLE,
171         INVALID_TABLE,
172         MONO_TABLE_METHOD,
173         MONO_TABLE_MEMBERREF,
174         INVALID_TABLE,
175
176 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
177         2, /*bits*/
178         4, /*tables*/
179         MONO_TABLE_MODULE,
180         MONO_TABLE_MODULEREF,
181         MONO_TABLE_ASSEMBLYREF,
182         MONO_TABLE_TYPEREF,
183
184 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
185         1, /*bits*/
186         2, /*tables*/
187         MONO_TABLE_TYPEDEF,
188         MONO_TABLE_METHOD
189 };
190
191 typedef struct {
192         guint32 rva;
193         guint32 size;
194         guint32 translated_offset;
195 } DataDirectory;
196
197 typedef struct {
198         guint32 offset;
199         guint32 size;
200 } OffsetAndSize;
201
202 typedef struct {
203         guint32 baseRVA;
204         guint32 baseOffset;
205         guint32 size;
206         guint32 rellocationsRVA;
207         guint16 numberOfRelocations;
208 } SectionHeader;
209
210 typedef struct {
211         guint32 row_count;
212         guint32 row_size;
213         guint32 offset;
214 } TableInfo;
215
216 typedef struct {
217         const char *data;
218         guint32 size;
219         GSList *errors;
220         int valid;
221         gboolean is_corlib;
222         MonoImage *image;
223         gboolean report_error;
224         int stage;
225
226         DataDirectory data_directories [16];
227         guint32 section_count;
228         SectionHeader *sections;
229
230         OffsetAndSize metadata_streams [5]; //offset from begin of the image
231 } VerifyContext;
232
233 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception)    \
234         do {    \
235                 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1);      \
236                 vinfo->info.status = __status;  \
237                 vinfo->info.message = ( __msg); \
238                 vinfo->exception_type = (__exception);  \
239                 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo);     \
240         } while (0)
241
242
243 #define ADD_ERROR(__ctx, __msg) \
244         do {    \
245                 if ((__ctx)->report_error) \
246                         ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
247                 (__ctx)->valid = 0; \
248                 return; \
249         } while (0)
250
251 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
252
253 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
254
255 static guint32
256 pe_signature_offset (VerifyContext *ctx)
257 {
258         return read32 (ctx->data + 0x3c);
259 }
260
261 static guint32
262 pe_header_offset (VerifyContext *ctx)
263 {
264         return read32 (ctx->data + 0x3c) + 4;
265 }
266
267 static gboolean
268 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
269 {
270         int i;
271
272         if (rva + size < rva) //overflow
273                 return FALSE;
274
275         if (ctx->stage > STAGE_PE) {
276                 MonoCLIImageInfo *iinfo = ctx->image->image_info;
277                 const int top = iinfo->cli_section_count;
278                 MonoSectionTable *tables = iinfo->cli_section_tables;
279                 int i;
280                 
281                 for (i = 0; i < top; i++) {
282                         guint32 base = tables->st_virtual_address;
283                         guint32 end = base + tables->st_raw_data_size;
284
285                         if (rva >= base && rva + size <= end)
286                                 return TRUE;
287
288                         /*if ((addr >= tables->st_virtual_address) &&
289                             (addr < tables->st_virtual_address + tables->st_raw_data_size)){
290
291                                 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
292                         }*/
293                         tables++;
294                 }
295                 return FALSE;
296         }
297
298         if (!ctx->sections)
299                 return FALSE;
300
301         for (i = 0; i < ctx->section_count; ++i) {
302                 guint32 base = ctx->sections [i].baseRVA;
303                 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
304                 if (rva >= base && rva + size <= end)
305                         return TRUE;
306         }
307         return FALSE;
308 }
309
310 static gboolean
311 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
312 {
313         if (dir->translated_offset > offset)
314                 return FALSE;
315         if (dir->size < size)
316                 return FALSE;
317         return offset + size <= dir->translated_offset + dir->size;
318 }
319
320 static gboolean
321 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
322 {
323         if (off->offset > offset)
324                 return FALSE;
325         
326         if (off->size < size)
327                 return FALSE;
328
329         return offset + size <= off->offset + off->size;
330 }
331
332 static guint32
333 translate_rva (VerifyContext *ctx, guint32 rva)
334 {
335         int i;
336
337         if (ctx->stage > STAGE_PE)
338                 return mono_cli_rva_image_map (ctx->image, rva);
339                 
340         if (!ctx->sections)
341                 return FALSE;
342
343         for (i = 0; i < ctx->section_count; ++i) {
344                 guint32 base = ctx->sections [i].baseRVA;
345                 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
346                 if (rva >= base && rva <= end) {
347                         guint32 res = (rva - base) + ctx->sections [i].baseOffset;
348                         /* double check */
349                         return res >= ctx->size ? INVALID_OFFSET : res;
350                 }
351         }
352
353         return INVALID_OFFSET;
354 }
355
356 static void
357 verify_msdos_header (VerifyContext *ctx)
358 {
359         guint32 lfanew;
360         if (ctx->size < 128)
361                 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
362         if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
363                 ADD_ERROR (ctx,  g_strdup ("Invalid MS-DOS watermark"));
364         lfanew = pe_signature_offset (ctx);
365         if (lfanew > ctx->size - 4)
366                 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
367 }
368
369 static void
370 verify_pe_header (VerifyContext *ctx)
371 {
372         guint32 offset = pe_signature_offset (ctx);
373         const char *pe_header = ctx->data + offset;
374         if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
375                 ADD_ERROR (ctx,  g_strdup ("Invalid PE header watermark"));
376         pe_header += 4;
377         offset += 4;
378
379         if (offset > ctx->size - 20)
380                 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
381         if (read16 (pe_header) != 0x14c)
382                 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
383 }
384
385 static void
386 verify_pe_optional_header (VerifyContext *ctx)
387 {
388         guint32 offset = pe_header_offset (ctx);
389         guint32 header_size, file_alignment;
390         const char *pe_header = ctx->data + offset;
391         const char *pe_optional_header = pe_header + 20;
392
393         header_size = read16 (pe_header + 16);
394         offset += 20;
395
396         if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
397                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
398
399         if (offset > ctx->size - header_size || header_size > ctx->size)
400                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
401
402         if (read16 (pe_optional_header) == 0x10b) {
403                 if (header_size != 224)
404                         ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
405
406                 /* LAMESPEC MS plays around this value and ignore it during validation
407                 if (read32 (pe_optional_header + 28) != 0x400000)
408                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
409                 if (read32 (pe_optional_header + 32) != 0x2000)
410                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
411                 file_alignment = read32 (pe_optional_header + 36);
412                 if (file_alignment != 0x200 && file_alignment != 0x1000)
413                         ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
414                 /* All the junk in the middle is irrelevant, specially for mono. */
415                 if (read32 (pe_optional_header + 92) > 0x10)
416                         ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
417         } else {
418                 if (read16 (pe_optional_header) == 0x20B)
419                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
420                 else
421                         ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
422         }
423 }
424
425 static void
426 load_section_table (VerifyContext *ctx)
427 {
428         int i;
429         SectionHeader *sections;
430         guint32 offset =  pe_header_offset (ctx);
431         const char *ptr = ctx->data + offset;
432         guint16 num_sections = ctx->section_count = read16 (ptr + 2);
433
434         offset += 244;/*FIXME, this constant is different under PE32+*/
435         ptr += 244;
436
437         if (num_sections * 40 > ctx->size - offset)
438                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
439
440         sections = ctx->sections = g_new0 (SectionHeader, num_sections);
441         for (i = 0; i < num_sections; ++i) {
442                 sections [i].size = read32 (ptr + 8);
443                 sections [i].baseRVA = read32 (ptr + 12);
444                 sections [i].baseOffset = read32 (ptr + 20);
445                 sections [i].rellocationsRVA = read32 (ptr + 24);
446                 sections [i].numberOfRelocations = read16 (ptr + 32);
447                 ptr += 40;
448         }
449
450         ptr = ctx->data + offset; /*reset it to the beggining*/
451         for (i = 0; i < num_sections; ++i) {
452                 guint32 raw_size, flags;
453                 if (sections [i].baseOffset == 0)
454                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
455                 if (sections [i].baseOffset >= ctx->size)
456                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
457                 if (sections [i].size > ctx->size - sections [i].baseOffset)
458                         ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
459
460                 raw_size = read32 (ptr + 16);
461                 if (raw_size < sections [i].size)
462                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
463
464                 if (raw_size > ctx->size - sections [i].baseOffset)
465                         ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
466
467                 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
468                         ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
469
470                 flags = read32 (ptr + 36);
471                 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
472                 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
473                         ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
474
475                 ptr += 40;
476         }
477 }
478
479 static gboolean
480 is_valid_data_directory (int i)
481 {
482         /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
483         return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6; 
484 }
485
486 static void
487 load_data_directories (VerifyContext *ctx)
488 {
489         guint32 offset =  pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
490         const char *ptr = ctx->data + offset;
491         int i;
492
493         for (i = 0; i < 16; ++i) {
494                 guint32 rva = read32 (ptr);
495                 guint32 size = read32 (ptr + 4);
496
497                 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
498                 if (i == CERTIFICATE_TABLE_IDX) {
499                         ptr += 8;
500                         continue;
501                 }
502                 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
503                         ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
504
505                 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
506                         ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
507
508                 ctx->data_directories [i].rva = rva;
509                 ctx->data_directories [i].size = size;
510                 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
511
512                 ptr += 8;
513         }
514 }
515
516 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
517
518 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
519
520 static void
521 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
522 {
523         const char *ptr;
524         guint32 hint_table_rva;
525
526         import_rva = translate_rva (ctx, import_rva);
527         g_assert (import_rva != INVALID_OFFSET);
528
529         hint_table_rva = read32 (ctx->data + import_rva);
530         if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
531                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
532
533         hint_table_rva = translate_rva (ctx, hint_table_rva);
534         g_assert (hint_table_rva != INVALID_OFFSET);
535         ptr = ctx->data + hint_table_rva + 2;
536
537         if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
538                 char name[SIZE_OF_CORMAIN];
539                 memcpy (name, ptr, SIZE_OF_CORMAIN);
540                 name [SIZE_OF_CORMAIN - 1] = 0;
541                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
542         }
543 }
544
545 static void
546 verify_import_table (VerifyContext *ctx)
547 {
548         DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
549         guint32 offset = it.translated_offset;
550         const char *ptr = ctx->data + offset;
551         guint32 name_rva, ilt_rva, iat_rva;
552
553         g_assert (offset != INVALID_OFFSET);
554
555         if (it.size < 40)
556                 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
557
558         ilt_rva = read32 (ptr);
559         if (!bounds_check_virtual_address (ctx, ilt_rva, 8))
560                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
561
562         name_rva = read32 (ptr + 12);
563         if (!bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
564                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
565
566         iat_rva = read32 (ptr + 16);
567         if (!bounds_check_virtual_address (ctx, iat_rva, 8))
568                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
569
570         if (iat_rva != ctx->data_directories [IAT_IDX].rva)
571                 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));
572
573         name_rva = translate_rva (ctx, name_rva);
574         g_assert (name_rva != INVALID_OFFSET);
575         ptr = ctx->data + name_rva;
576
577         if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
578                 char name[SIZE_OF_MSCOREE];
579                 memcpy (name, ptr, SIZE_OF_MSCOREE);
580                 name [SIZE_OF_MSCOREE - 1] = 0;
581                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
582         }
583         
584         verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
585         CHECK_ERROR ();
586         verify_hint_name_table (ctx, iat_rva, "Import Address Table");
587 }
588
589 static void
590 verify_resources_table (VerifyContext *ctx)
591 {
592         DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
593         guint32 offset;
594         guint16 named_entries, id_entries;
595         const char *ptr, *root, *end;
596
597         if (it.rva == 0)
598                 return;
599
600         if (it.size < 16)
601                 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));
602
603         offset = it.translated_offset;
604         root = ptr = ctx->data + offset;
605         end = root + it.size;
606
607         g_assert (offset != INVALID_OFFSET);
608
609         named_entries = read16 (ptr + 12);
610         id_entries = read16 (ptr + 14);
611
612         if ((named_entries + id_entries) * 8 + 16 > it.size)
613                 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));
614
615         /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource () 
616         if (named_entries || id_entries)
617                 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
618         */
619 }
620
621 /*----------nothing from here on can use data_directory---*/
622
623 static DataDirectory
624 get_data_dir (VerifyContext *ctx, int idx)
625 {
626         MonoCLIImageInfo *iinfo = ctx->image->image_info;
627         MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
628         DataDirectory res;
629
630         entry += idx;
631         res.rva = entry->rva;
632         res.size = entry->size;
633         res.translated_offset = translate_rva (ctx, res.rva);
634         return res;
635
636 }
637 static void
638 verify_cli_header (VerifyContext *ctx)
639 {
640         DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
641         guint32 offset;
642         const char *ptr;
643         int i;
644
645         if (it.rva == 0)
646                 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
647
648         if (it.size != 72)
649                 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
650
651         offset = it.translated_offset;
652         ptr = ctx->data + offset;
653
654         g_assert (offset != INVALID_OFFSET);
655
656         if (read16 (ptr) != 72)
657                 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
658
659         if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
660                 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
661
662
663         if (!read32 (ptr + 8) || !read32 (ptr + 12))
664                 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
665
666         if ((read32 (ptr + 16) & ~0x0001000B) != 0)
667                 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
668
669         ptr += 24;
670         for (i = 0; i < 6; ++i) {
671                 guint32 rva = read32 (ptr);
672                 guint32 size = read32 (ptr + 4);
673
674                 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
675                         ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
676
677                 ptr += 8;
678
679                 if (rva && i > 1)
680                         ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
681         }
682 }
683
684 static guint32
685 pad4 (guint32 offset)
686 {
687         if (offset & 0x3) //pad to the next 4 byte boundary
688                 offset = (offset & ~0x3) + 4;
689         return offset;
690 }
691
692 static void
693 verify_metadata_header (VerifyContext *ctx)
694 {
695         int i;
696         DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
697         guint32 offset;
698         const char *ptr;
699
700         offset = it.translated_offset;
701         ptr = ctx->data + offset;
702         g_assert (offset != INVALID_OFFSET);
703
704         //build a directory entry for the metadata root
705         ptr += 8;
706         it.rva = read32 (ptr);
707         ptr += 4;
708         it.size = read32 (ptr);
709         it.translated_offset = offset = translate_rva (ctx, it.rva);
710
711         ptr = ctx->data + offset;
712         g_assert (offset != INVALID_OFFSET);
713
714         if (it.size < 20)
715                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
716
717         if (read32 (ptr) != 0x424A5342)
718                 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
719
720         offset = pad4 (offset + 16 + read32 (ptr + 12));
721
722         if (!bounds_check_datadir (&it, offset, 4))
723                 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));
724
725         ptr = ctx->data + offset; //move to streams header 
726
727         if (read16 (ptr + 2) != 5)
728                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section have %d streams (it must have exactly 5)", read16 (ptr + 2)));
729
730         ptr += 4;
731         offset += 4;
732
733         for (i = 0; i < 5; ++i) {
734                 guint32 stream_off, stream_size;
735                 int string_size, stream_idx;
736
737                 if (!bounds_check_datadir (&it, offset, 8))
738                         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));
739
740                 stream_off = it.translated_offset + read32 (ptr);
741                 stream_size = read32 (ptr + 4);
742
743                 if (!bounds_check_datadir (&it,  stream_off, stream_size))
744                         ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
745
746                 ptr += 8;
747                 offset += 8;
748
749                 for (string_size = 0; string_size < 32; ++string_size) {
750                         if (!bounds_check_datadir (&it, offset++, 1))
751                                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
752                         if (!ptr [string_size])
753                                 break;
754                 }
755
756                 if (ptr [string_size])
757                         ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
758
759                 if (!strncmp ("#Strings", ptr, 9))
760                         stream_idx = STRINGS_STREAM;
761                 else if (!strncmp ("#US", ptr, 4))
762                         stream_idx = USER_STRINGS_STREAM;
763                 else if (!strncmp ("#Blob", ptr, 6))
764                         stream_idx = BLOB_STREAM;
765                 else if (!strncmp ("#GUID", ptr, 6))
766                         stream_idx = GUID_STREAM;
767                 else if (!strncmp ("#~", ptr, 3))
768                         stream_idx = TILDE_STREAM;
769                 else
770                         ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
771
772                 if (ctx->metadata_streams [stream_idx].offset != 0)
773                         ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
774
775                 ctx->metadata_streams [stream_idx].offset = stream_off;
776                 ctx->metadata_streams [stream_idx].size = stream_size;
777
778                 offset = pad4 (offset);
779                 ptr = ctx->data + offset;
780         }
781 }
782
783 static void
784 verify_tables_schema (VerifyContext *ctx)
785 {
786         OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
787         unsigned offset = tables_area.offset;
788         const char *ptr = ctx->data + offset;
789         guint64 valid_tables;
790         guint32 count;
791         int i;
792
793         //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
794         if (tables_area.size < 24)
795                 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
796
797         //printf ("ptr %x %x\n", ptr[4], ptr[5]);
798         if (ptr [4] != 2 && ptr [4] != 1)
799                 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
800         if (ptr [5] != 0)
801                 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
802
803         if ((ptr [6] & ~0x7) != 0)
804                 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]));
805
806         valid_tables = read64 (ptr + 8);
807         count = 0;
808         for (i = 0; i < 64; ++i) {
809                 if (!(valid_tables & ((guint64)1 << i)))
810                         continue;
811
812                 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
813                   Unused: 0x1E 0x1F 0x2D-0x3F
814                   We don't care about the MS extensions.*/
815                 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
816                         ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
817                 if (i == 0x1E || i == 0x1F || i >= 0x2D)
818                         ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
819                 ++count;
820         }
821
822         if (tables_area.size < 24 + count * 4)
823                 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));
824         ptr += 24;
825
826         for (i = 0; i < 64; ++i) {
827                 if (valid_tables & ((guint64)1 << i)) {
828                         guint32 row_count = read32 (ptr);
829                         if (row_count > (1 << 25) - 1)
830                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count, mono only supports ", i));
831                         ptr += 4;
832                 }
833         }
834 }
835
836 /*----------nothing from here on can use data_directory or metadata_streams ---*/
837
838 static guint32
839 get_col_offset (VerifyContext *ctx, int table, int column)
840 {
841         guint32 bitfield = ctx->image->tables [table].size_bitfield;
842         guint32 offset = 0;
843
844         while (column-- > 0)
845                 offset += mono_metadata_table_size (bitfield, column);
846
847         return offset;
848 }
849
850 static guint32
851 get_col_size (VerifyContext *ctx, int table, int column)
852 {
853         return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
854 }
855
856 static OffsetAndSize
857 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
858 {
859         OffsetAndSize res;
860         res.offset = header->data - ctx->data;
861         res.size = header->size;
862
863         return res;
864 }
865
866 static gboolean
867 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
868 {
869         OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
870         glong length;
871         const char *data = ctx->data + strings.offset;
872
873         if (offset >= strings.size)
874                 return FALSE;
875         if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing  
876                 return FALSE;
877
878         if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
879                 return FALSE;
880         return allow_empty || length > 0;
881 }
882
883 static gboolean
884 is_valid_string (VerifyContext *ctx, guint32 offset)
885 {
886         return is_valid_string_full (ctx, offset, TRUE);
887 }
888
889 static gboolean
890 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
891 {
892         return is_valid_string_full (ctx, offset, FALSE);
893 }
894
895 static gboolean
896 is_valid_guid (VerifyContext *ctx, guint32 offset)
897 {
898         OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
899         return guids.size >= 8 && guids.size - 8 >= offset;
900 }
901
902 static guint32
903 get_coded_index_token (int token_kind, guint32 coded_token)
904 {
905         guint32 bits = coded_index_desc [token_kind];
906         return coded_token >> bits;
907 }
908
909 static guint32
910 make_coded_token (int kind, guint32 table, guint32 table_idx)
911 {
912         guint32 bits = coded_index_desc [kind++];
913         guint32 tables = coded_index_desc [kind++];
914         guint32 i;
915         for (i = 0; i < tables; ++i) {
916                 if (coded_index_desc [kind++] == table)
917                         return ((table_idx + 1) << bits) | i; 
918         }
919         g_assert_not_reached ();
920         return -1;
921 }
922
923 static gboolean
924 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
925 {
926         guint32 bits = coded_index_desc [token_kind++];
927         guint32 table_count = coded_index_desc [token_kind++];
928         guint32 table = coded_token & ((1 << bits) - 1);
929         guint32 token = coded_token >> bits;
930
931         if (table >= table_count)
932                 return FALSE;
933
934         /*token_kind points to the first table idx*/
935         table = coded_index_desc [token_kind + table];
936
937         if (table == INVALID_TABLE)
938                 return FALSE;
939         return token <= ctx->image->tables [table].rows;
940 }
941
942 typedef struct {
943         guint32 token;
944         guint32 col_size;
945         guint32 col_offset;
946 } RowLocator;
947
948 static int
949 token_locator (const void *a, const void *b)
950 {
951         RowLocator *loc = (RowLocator *)a;
952         unsigned const char *row = (unsigned const char *)b;
953         guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
954
955         VERIFIER_DEBUG ( printf ("\tfound token %x\n", token) );
956         return (int)loc->token - (int)token;
957 }
958
959 static int
960 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
961 {
962         MonoTableInfo *tinfo = &ctx->image->tables [table];
963         RowLocator locator;
964         const char *res, *base;
965         locator.token = coded_token;
966         locator.col_offset = get_col_offset (ctx, table, column);
967         locator.col_size = get_col_size (ctx, table, column);
968         base = tinfo->base;
969
970         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) );
971         res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
972         if (!res)
973                 return -1;
974
975         return (res - base) / tinfo->rows;
976 }
977
978 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
979 static const char*
980 get_string_ptr (VerifyContext *ctx, guint offset)
981 {
982         return ctx->image->heap_strings.data + offset;
983 }
984
985 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
986 static int
987 string_cmp (VerifyContext *ctx, const char *str, guint offset)
988 {
989         if (offset == 0)
990                 return strcmp (str, "");
991
992         return strcmp (str, get_string_ptr (ctx, offset));
993 }
994
995 static gboolean
996 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
997 {
998         return ctx->is_corlib && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAME]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAMESPACE]);
999 }
1000
1001 static gboolean
1002 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1003 {
1004         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1005         //TODO do proper verification
1006         return blob.size >= 2 && blob.size - 2 >= offset;
1007 }
1008
1009 static gboolean
1010 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1011 {
1012         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1013         //TODO do proper verification
1014         return blob.size >= 2 && blob.size - 2 >= offset;
1015 }
1016
1017 static gboolean
1018 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1019 {
1020         //TODO do proper method header validation
1021         return mono_cli_rva_image_map (ctx->image, rva) != INVALID_ADDRESS;
1022 }
1023
1024 static void
1025 verify_module_table (VerifyContext *ctx)
1026 {
1027         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1028         guint32 data [MONO_MODULE_SIZE];
1029
1030         if (table->rows != 1)
1031                 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1032
1033         mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1034
1035         if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1036                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1037
1038         if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1039                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1040
1041         if (data [MONO_MODULE_ENC] != 0)
1042                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1043
1044         if (data [MONO_MODULE_ENCBASE] != 0)
1045                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1046 }
1047
1048 static void
1049 verify_typeref_table (VerifyContext *ctx)
1050 {
1051         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1052         guint32 data [MONO_TYPEREF_SIZE];
1053         int i;
1054
1055         for (i = 0; i < table->rows; ++i) {
1056                 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1057                 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1058                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1059                 
1060                 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1061                         ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1062
1063                 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1064                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1065
1066                 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1067                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
1068         }
1069 }
1070
1071 /*bits 9,11,14,15,19,21,24-31 */
1072 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 9) | (1 << 11) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
1073 static void
1074 verify_typedef_table (VerifyContext *ctx)
1075 {
1076         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1077         guint32 data [MONO_TYPEDEF_SIZE];
1078         guint32 fieldlist = 1, methodlist = 1;
1079         int i;
1080
1081         if (table->rows == 0)
1082                 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
1083
1084         for (i = 0; i < table->rows; ++i) {
1085                 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
1086                 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
1087                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
1088
1089                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
1090                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
1091
1092                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
1093                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1094
1095                 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
1096                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1097
1098                 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
1099                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
1100
1101                 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1102                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
1103
1104                 if (i == 0) {
1105                         if (data [MONO_TYPEDEF_EXTENDS] != 0)
1106                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
1107                 } else {
1108                         if (typedef_is_system_object (ctx, data) && data [MONO_TYPEDEF_EXTENDS] != 0)
1109                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
1110         
1111                         if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
1112                                 if (data [MONO_TYPEDEF_EXTENDS])
1113                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
1114                                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
1115                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
1116                         } else {
1117                                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1118                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
1119         
1120                                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS])) 
1121                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
1122                         }
1123                 }
1124
1125                 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
1126                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
1127
1128                 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
1129                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
1130
1131                 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
1132                         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));
1133
1134                 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
1135                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
1136
1137                 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
1138                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
1139
1140                 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
1141                         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));
1142
1143
1144                 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
1145                 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
1146         }
1147 }
1148
1149 /*bits 3,11,14 */
1150 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
1151 static void
1152 verify_field_table (VerifyContext *ctx)
1153 {
1154         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
1155         guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
1156         int i;
1157
1158         module_field_list = (guint32)-1;
1159         if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1160                 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1161                 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
1162         }
1163         
1164         for (i = 0; i < table->rows; ++i) {
1165                 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
1166                 flags = data [MONO_FIELD_FLAGS];
1167
1168                 if (flags & INVALID_FIELD_FLAG_BITS)
1169                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
1170
1171                 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)         
1172                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
1173
1174                 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
1175                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
1176
1177                 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
1178                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
1179
1180                 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
1181                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
1182
1183                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
1184                                 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
1185                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
1186
1187                 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
1188                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1189                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1190
1191                 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
1192                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1193                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
1194
1195                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
1196                                 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
1197                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1198
1199                 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
1200                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
1201
1202                 //TODO verify contant flag
1203                 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
1204                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
1205
1206                 if (i + 1 < module_field_list) {
1207                         guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
1208                         if (!(flags & FIELD_ATTRIBUTE_STATIC))
1209                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
1210                         if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
1211                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
1212                 }
1213         }
1214 }
1215
1216 /*bits 6,8,9,10,11,13,14,15*/
1217 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
1218 static void
1219 verify_method_table (VerifyContext *ctx)
1220 {
1221         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1222         guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
1223         guint32 paramlist = 1;
1224         gboolean is_ctor, is_cctor;
1225         const char *name;
1226         int i;
1227
1228         module_method_list = (guint32)-1;
1229         if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1230                 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1231                 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
1232         }
1233
1234         for (i = 0; i < table->rows; ++i) {
1235                 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
1236                 rva = data [MONO_METHOD_RVA];
1237                 implflags = data [MONO_METHOD_IMPLFLAGS];
1238                 flags = data [MONO_METHOD_FLAGS];
1239                 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
1240                 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
1241                 
1242
1243                 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
1244                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
1245
1246                 if (access == 0x7)
1247                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
1248
1249                 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
1250                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
1251
1252                 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
1253                 is_ctor = !strcmp (".ctor", name);
1254                 is_cctor = !strcmp (".cctor", name);
1255
1256                 if ((is_ctor || is_cctor) &&
1257                         search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
1258                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
1259
1260                 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
1261                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
1262                 
1263                 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
1264                         if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1265                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
1266                         if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
1267                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
1268                 }
1269
1270                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
1271                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
1272
1273                 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
1274                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
1275
1276                 //XXX no checks against cas stuff 10,11,12,13)
1277
1278                 //TODO check iface with .ctor (15,16)
1279
1280                 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
1281                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token %08x", i, data [MONO_METHOD_SIGNATURE]));
1282
1283                 if (i + 1 < module_method_list) {
1284                         if (!(flags & METHOD_ATTRIBUTE_STATIC))
1285                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
1286                         if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
1287                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
1288                         if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
1289                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
1290                 }
1291
1292                 //TODO check valuetype for synchronized
1293
1294                 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
1295                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
1296
1297                 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
1298                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
1299
1300                 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && 
1301                                 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1302                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
1303
1304                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
1305                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
1306
1307                 //TODO check signature contents
1308
1309                 if (rva) {
1310                         if (flags & METHOD_ATTRIBUTE_ABSTRACT)
1311                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
1312                         if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
1313                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
1314                         if (!is_valid_method_header (ctx, rva))
1315                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
1316                 } else {
1317                         if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1318                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
1319                 }
1320
1321                 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
1322                         if (rva)
1323                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
1324                         if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
1325                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
1326                 }
1327                 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
1328                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
1329
1330                 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
1331                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
1332
1333                 if (data [MONO_METHOD_PARAMLIST] == 0)
1334                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
1335
1336                 if (data [MONO_METHOD_PARAMLIST] < paramlist)
1337                         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));
1338
1339                 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
1340                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
1341
1342                 paramlist = data [MONO_METHOD_PARAMLIST];
1343
1344         }
1345 }
1346
1347 static guint32
1348 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
1349 {
1350         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1351         guint32 row = *current_method;
1352         guint32 paramlist, tmp;
1353
1354
1355         paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
1356         while (row < table->rows) {
1357                 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
1358                 if (tmp > paramlist) {
1359                         *current_method = row;
1360                         return tmp - paramlist;
1361                 }
1362                 ++row;
1363         }
1364
1365         /*no more methods, all params apply to the last one*/
1366         *current_method = table->rows;
1367         return (guint32)-1;
1368 }
1369
1370
1371 #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))
1372 static void
1373 verify_param_table (VerifyContext *ctx)
1374 {
1375         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
1376         guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
1377         gboolean first_param = TRUE;
1378         int i;
1379
1380         remaining_params = get_next_param_count (ctx, &current_method);
1381
1382         for (i = 0; i < table->rows; ++i) {
1383                 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
1384                 flags = data [MONO_PARAM_FLAGS];
1385
1386                 if (flags & INVALID_PARAM_FLAGS_BITS)
1387                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
1388
1389                 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
1390                         if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
1391                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
1392                 } else {
1393                         if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
1394                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
1395                 }
1396
1397                 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)
1398                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
1399
1400                 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
1401                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
1402
1403                 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
1404                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
1405
1406                 first_param = FALSE;
1407                 sequence = data [MONO_PARAM_SEQUENCE];
1408                 if (--remaining_params == 0) {
1409                         remaining_params = get_next_param_count (ctx, &current_method);
1410                         first_param = TRUE;
1411                 }
1412         }
1413 }
1414
1415 static void
1416 verify_interfaceimpl_table (VerifyContext *ctx)
1417 {
1418         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
1419         guint32 data [MONO_INTERFACEIMPL_SIZE];
1420         int i;
1421
1422         for (i = 0; i < table->rows; ++i) {
1423                 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
1424                 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
1425                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
1426
1427                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
1428                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
1429
1430                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
1431                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
1432         }
1433 }
1434
1435 static void
1436 verify_tables_data (VerifyContext *ctx)
1437 {
1438         OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
1439         guint32 size = 0, tables_offset;
1440         int i;
1441
1442         for (i = 0; i < 0x2D; ++i) {
1443                 MonoTableInfo *table = &ctx->image->tables [i];
1444                 guint32 tmp_size;
1445                 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
1446                 if (tmp_size < size) {
1447                         size = 0;
1448                         break;
1449                 }
1450                 size = tmp_size;                        
1451         }
1452
1453         if (size == 0)
1454                 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
1455
1456         tables_offset = ctx->image->tables_base - ctx->data;
1457         if (!bounds_check_offset (&tables_area, tables_offset, size))
1458                 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)));
1459
1460         verify_module_table (ctx);
1461         CHECK_ERROR ();
1462         verify_typeref_table (ctx);
1463         CHECK_ERROR ();
1464         verify_typedef_table (ctx);
1465         CHECK_ERROR ();
1466         verify_field_table (ctx);
1467         CHECK_ERROR ();
1468         verify_method_table (ctx);
1469         CHECK_ERROR ();
1470         verify_param_table (ctx);
1471         CHECK_ERROR ();
1472         verify_interfaceimpl_table (ctx);
1473 }
1474
1475 static gboolean
1476 mono_verifier_is_corlib (MonoImage *image)
1477 {
1478         gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ? 
1479                         TRUE : mono_security_core_clr_is_platform_image (image);
1480
1481         return trusted_location && !strcmp ("mscorlib.dll", image->name);
1482 }
1483
1484 static void
1485 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
1486 {
1487         memset (ctx, 0, sizeof (VerifyContext));
1488         ctx->image = image;
1489         ctx->report_error = error_list != NULL;
1490         ctx->valid = 1;
1491         ctx->size = image->raw_data_len;
1492         ctx->data = image->raw_data;
1493         ctx->is_corlib = mono_verifier_is_corlib (image);       
1494 }
1495
1496 static gboolean
1497 cleanup_context (VerifyContext *ctx, GSList **error_list)
1498 {
1499         g_free (ctx->sections);
1500         if (error_list)
1501                 *error_list = ctx->errors;
1502         else
1503                 mono_free_verify_list (ctx->errors);
1504         return ctx->valid;      
1505 }
1506
1507 gboolean
1508 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
1509 {
1510         VerifyContext ctx;
1511
1512         if (!mono_verifier_is_enabled_for_image (image))
1513                 return TRUE;
1514
1515         init_verify_context (&ctx, image, error_list);
1516         ctx.stage = STAGE_PE;
1517
1518         verify_msdos_header (&ctx);
1519         CHECK_STATE();
1520         verify_pe_header (&ctx);
1521         CHECK_STATE();
1522         verify_pe_optional_header (&ctx);
1523         CHECK_STATE();
1524         load_section_table (&ctx);
1525         CHECK_STATE();
1526         load_data_directories (&ctx);
1527         CHECK_STATE();
1528         verify_import_table (&ctx);
1529         CHECK_STATE();
1530         /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
1531         verify_resources_table (&ctx);
1532
1533 cleanup:
1534         return cleanup_context (&ctx, error_list);
1535 }
1536
1537 gboolean
1538 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
1539 {
1540         VerifyContext ctx;
1541
1542         if (!mono_verifier_is_enabled_for_image (image))
1543                 return TRUE;
1544
1545         init_verify_context (&ctx, image, error_list);
1546         ctx.stage = STAGE_CLI;
1547
1548         verify_cli_header (&ctx);
1549         CHECK_STATE();
1550         verify_metadata_header (&ctx);
1551         CHECK_STATE();
1552         verify_tables_schema (&ctx);
1553
1554 cleanup:
1555         return cleanup_context (&ctx, error_list);
1556 }
1557
1558 gboolean
1559 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
1560 {
1561         VerifyContext ctx;
1562
1563         if (!mono_verifier_is_enabled_for_image (image))
1564                 return TRUE;
1565
1566         init_verify_context (&ctx, image, error_list);
1567         ctx.stage = STAGE_TABLES;
1568
1569         verify_tables_data (&ctx);
1570
1571         return cleanup_context (&ctx, error_list);
1572 }