2009-08-25 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         20, /*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         MONO_TABLE_GENERICPARAM,
121
122 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
123         1, /*bits*/
124         2, /*tables*/
125         MONO_TABLE_FIELD,
126         MONO_TABLE_PARAM,
127
128 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
129         2, /*bits*/
130         3, /*tables*/
131         MONO_TABLE_TYPEDEF,
132         MONO_TABLE_METHOD,
133         MONO_TABLE_ASSEMBLY,
134
135 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
136         3, /*bits*/
137         5, /*tables*/
138         MONO_TABLE_TYPEDEF,
139         MONO_TABLE_TYPEREF,
140         MONO_TABLE_MODULE,
141         MONO_TABLE_METHOD,
142         MONO_TABLE_TYPESPEC,
143
144 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
145         1, /*bits*/
146         2, /*tables*/
147         MONO_TABLE_EVENT,
148         MONO_TABLE_PROPERTY,
149
150 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
151         1, /*bits*/
152         2, /*tables*/
153         MONO_TABLE_METHOD,
154         MONO_TABLE_MEMBERREF,
155
156 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
157         1, /*bits*/
158         2, /*tables*/
159         MONO_TABLE_FIELD,
160         MONO_TABLE_METHOD,
161
162 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
163         2, /*bits*/
164         3, /*tables*/
165         MONO_TABLE_FILE,
166         MONO_TABLE_ASSEMBLYREF,
167         MONO_TABLE_EXPORTEDTYPE,
168
169 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
170         3, /*bits*/
171         5, /*tables*/
172         INVALID_TABLE,
173         INVALID_TABLE,
174         MONO_TABLE_METHOD,
175         MONO_TABLE_MEMBERREF,
176         INVALID_TABLE,
177
178 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
179         2, /*bits*/
180         4, /*tables*/
181         MONO_TABLE_MODULE,
182         MONO_TABLE_MODULEREF,
183         MONO_TABLE_ASSEMBLYREF,
184         MONO_TABLE_TYPEREF,
185
186 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
187         1, /*bits*/
188         2, /*tables*/
189         MONO_TABLE_TYPEDEF,
190         MONO_TABLE_METHOD
191 };
192
193 typedef struct {
194         guint32 rva;
195         guint32 size;
196         guint32 translated_offset;
197 } DataDirectory;
198
199 typedef struct {
200         guint32 offset;
201         guint32 size;
202 } OffsetAndSize;
203
204 typedef struct {
205         guint32 baseRVA;
206         guint32 baseOffset;
207         guint32 size;
208         guint32 rellocationsRVA;
209         guint16 numberOfRelocations;
210 } SectionHeader;
211
212 typedef struct {
213         guint32 row_count;
214         guint32 row_size;
215         guint32 offset;
216 } TableInfo;
217
218 typedef struct {
219         const char *data;
220         guint32 size;
221         GSList *errors;
222         int valid;
223         MonoImage *image;
224         gboolean report_error;
225         gboolean report_warning;
226         int stage;
227
228         DataDirectory data_directories [16];
229         guint32 section_count;
230         SectionHeader *sections;
231
232         OffsetAndSize metadata_streams [5]; //offset from begin of the image
233 } VerifyContext;
234
235 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception)    \
236         do {    \
237                 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1);      \
238                 vinfo->info.status = __status;  \
239                 vinfo->info.message = ( __msg); \
240                 vinfo->exception_type = (__exception);  \
241                 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo);     \
242         } while (0)
243
244 #define ADD_WARNING(__ctx, __msg)       \
245         do {    \
246                 if ((__ctx)->report_warning) \
247                         ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
248                 (__ctx)->valid = 0; \
249                 return; \
250         } while (0)
251
252 #define ADD_ERROR(__ctx, __msg) \
253         do {    \
254                 if ((__ctx)->report_error) \
255                         ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
256                 (__ctx)->valid = 0; \
257                 return; \
258         } while (0)
259
260 #define FAIL(__ctx, __msg)      \
261         do {    \
262                 if ((__ctx)->report_error) \
263                         ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
264                 (__ctx)->valid = 0; \
265                 return FALSE; \
266         } while (0)
267
268 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
269
270 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
271
272 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
273 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
274
275 #if SIZEOF_VOID_P == 4
276 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
277 #else
278 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
279 #endif
280
281 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
282 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
283
284 static const char *
285 dword_align (const char *ptr)
286 {
287 #if SIZEOF_VOID_P == 8
288         return (const char *) (((guint64) (ptr + 3)) & ~3);
289 #else
290         return (const char *) (((guint32) (ptr + 3)) & ~3);
291 #endif
292 }
293
294 static guint32
295 pe_signature_offset (VerifyContext *ctx)
296 {
297         return read32 (ctx->data + 0x3c);
298 }
299
300 static guint32
301 pe_header_offset (VerifyContext *ctx)
302 {
303         return read32 (ctx->data + 0x3c) + 4;
304 }
305
306 static gboolean
307 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
308 {
309         int i;
310
311         if (rva + size < rva) //overflow
312                 return FALSE;
313
314         if (ctx->stage > STAGE_PE) {
315                 MonoCLIImageInfo *iinfo = ctx->image->image_info;
316                 const int top = iinfo->cli_section_count;
317                 MonoSectionTable *tables = iinfo->cli_section_tables;
318                 int i;
319                 
320                 for (i = 0; i < top; i++) {
321                         guint32 base = tables->st_virtual_address;
322                         guint32 end = base + tables->st_raw_data_size;
323
324                         if (rva >= base && rva + size <= end)
325                                 return TRUE;
326
327                         /*if ((addr >= tables->st_virtual_address) &&
328                             (addr < tables->st_virtual_address + tables->st_raw_data_size)){
329
330                                 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
331                         }*/
332                         tables++;
333                 }
334                 return FALSE;
335         }
336
337         if (!ctx->sections)
338                 return FALSE;
339
340         for (i = 0; i < ctx->section_count; ++i) {
341                 guint32 base = ctx->sections [i].baseRVA;
342                 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
343                 if (rva >= base && rva + size <= end)
344                         return TRUE;
345         }
346         return FALSE;
347 }
348
349 static gboolean
350 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
351 {
352         if (dir->translated_offset > offset)
353                 return FALSE;
354         if (dir->size < size)
355                 return FALSE;
356         return offset + size <= dir->translated_offset + dir->size;
357 }
358
359 static gboolean
360 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
361 {
362         if (off->offset > offset)
363                 return FALSE;
364         
365         if (off->size < size)
366                 return FALSE;
367
368         return offset + size <= off->offset + off->size;
369 }
370
371 static guint32
372 translate_rva (VerifyContext *ctx, guint32 rva)
373 {
374         int i;
375
376         if (ctx->stage > STAGE_PE)
377                 return mono_cli_rva_image_map (ctx->image, rva);
378                 
379         if (!ctx->sections)
380                 return FALSE;
381
382         for (i = 0; i < ctx->section_count; ++i) {
383                 guint32 base = ctx->sections [i].baseRVA;
384                 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
385                 if (rva >= base && rva <= end) {
386                         guint32 res = (rva - base) + ctx->sections [i].baseOffset;
387                         /* double check */
388                         return res >= ctx->size ? INVALID_OFFSET : res;
389                 }
390         }
391
392         return INVALID_OFFSET;
393 }
394
395 static void
396 verify_msdos_header (VerifyContext *ctx)
397 {
398         guint32 lfanew;
399         if (ctx->size < 128)
400                 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
401         if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
402                 ADD_ERROR (ctx,  g_strdup ("Invalid MS-DOS watermark"));
403         lfanew = pe_signature_offset (ctx);
404         if (lfanew > ctx->size - 4)
405                 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
406 }
407
408 static void
409 verify_pe_header (VerifyContext *ctx)
410 {
411         guint32 offset = pe_signature_offset (ctx);
412         const char *pe_header = ctx->data + offset;
413         if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
414                 ADD_ERROR (ctx,  g_strdup ("Invalid PE header watermark"));
415         pe_header += 4;
416         offset += 4;
417
418         if (offset > ctx->size - 20)
419                 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
420         if (read16 (pe_header) != 0x14c)
421                 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
422 }
423
424 static void
425 verify_pe_optional_header (VerifyContext *ctx)
426 {
427         guint32 offset = pe_header_offset (ctx);
428         guint32 header_size, file_alignment;
429         const char *pe_header = ctx->data + offset;
430         const char *pe_optional_header = pe_header + 20;
431
432         header_size = read16 (pe_header + 16);
433         offset += 20;
434
435         if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
436                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
437
438         if (offset > ctx->size - header_size || header_size > ctx->size)
439                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
440
441         if (read16 (pe_optional_header) == 0x10b) {
442                 if (header_size != 224)
443                         ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
444
445                 /* LAMESPEC MS plays around this value and ignore it during validation
446                 if (read32 (pe_optional_header + 28) != 0x400000)
447                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
448                 if (read32 (pe_optional_header + 32) != 0x2000)
449                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
450                 file_alignment = read32 (pe_optional_header + 36);
451                 if (file_alignment != 0x200 && file_alignment != 0x1000)
452                         ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
453                 /* All the junk in the middle is irrelevant, specially for mono. */
454                 if (read32 (pe_optional_header + 92) > 0x10)
455                         ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
456         } else {
457                 if (read16 (pe_optional_header) == 0x20B)
458                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
459                 else
460                         ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
461         }
462 }
463
464 static void
465 load_section_table (VerifyContext *ctx)
466 {
467         int i;
468         SectionHeader *sections;
469         guint32 offset =  pe_header_offset (ctx);
470         const char *ptr = ctx->data + offset;
471         guint16 num_sections = ctx->section_count = read16 (ptr + 2);
472
473         offset += 244;/*FIXME, this constant is different under PE32+*/
474         ptr += 244;
475
476         if (num_sections * 40 > ctx->size - offset)
477                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
478
479         sections = ctx->sections = g_new0 (SectionHeader, num_sections);
480         for (i = 0; i < num_sections; ++i) {
481                 sections [i].size = read32 (ptr + 8);
482                 sections [i].baseRVA = read32 (ptr + 12);
483                 sections [i].baseOffset = read32 (ptr + 20);
484                 sections [i].rellocationsRVA = read32 (ptr + 24);
485                 sections [i].numberOfRelocations = read16 (ptr + 32);
486                 ptr += 40;
487         }
488
489         ptr = ctx->data + offset; /*reset it to the beggining*/
490         for (i = 0; i < num_sections; ++i) {
491                 guint32 raw_size, flags;
492                 if (sections [i].baseOffset == 0)
493                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
494                 if (sections [i].baseOffset >= ctx->size)
495                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
496                 if (sections [i].size > ctx->size - sections [i].baseOffset)
497                         ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
498
499                 raw_size = read32 (ptr + 16);
500                 if (raw_size < sections [i].size)
501                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
502
503                 if (raw_size > ctx->size - sections [i].baseOffset)
504                         ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
505
506                 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
507                         ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
508
509                 flags = read32 (ptr + 36);
510                 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
511                 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
512                         ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
513
514                 ptr += 40;
515         }
516 }
517
518 static gboolean
519 is_valid_data_directory (int i)
520 {
521         /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
522         return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6; 
523 }
524
525 static void
526 load_data_directories (VerifyContext *ctx)
527 {
528         guint32 offset =  pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
529         const char *ptr = ctx->data + offset;
530         int i;
531
532         for (i = 0; i < 16; ++i) {
533                 guint32 rva = read32 (ptr);
534                 guint32 size = read32 (ptr + 4);
535
536                 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
537                 if (i == CERTIFICATE_TABLE_IDX) {
538                         ptr += 8;
539                         continue;
540                 }
541                 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
542                         ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
543
544                 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
545                         ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
546
547                 ctx->data_directories [i].rva = rva;
548                 ctx->data_directories [i].size = size;
549                 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
550
551                 ptr += 8;
552         }
553 }
554
555 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
556
557 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
558
559 static void
560 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
561 {
562         const char *ptr;
563         guint32 hint_table_rva;
564
565         import_rva = translate_rva (ctx, import_rva);
566         g_assert (import_rva != INVALID_OFFSET);
567
568         hint_table_rva = read32 (ctx->data + import_rva);
569         if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
570                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
571
572         hint_table_rva = translate_rva (ctx, hint_table_rva);
573         g_assert (hint_table_rva != INVALID_OFFSET);
574         ptr = ctx->data + hint_table_rva + 2;
575
576         if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
577                 char name[SIZE_OF_CORMAIN];
578                 memcpy (name, ptr, SIZE_OF_CORMAIN);
579                 name [SIZE_OF_CORMAIN - 1] = 0;
580                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
581         }
582 }
583
584 static void
585 verify_import_table (VerifyContext *ctx)
586 {
587         DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
588         guint32 offset = it.translated_offset;
589         const char *ptr = ctx->data + offset;
590         guint32 name_rva, ilt_rva, iat_rva;
591
592         g_assert (offset != INVALID_OFFSET);
593
594         if (it.size < 40)
595                 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
596
597         ilt_rva = read32 (ptr);
598         if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
599                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
600
601         name_rva = read32 (ptr + 12);
602         if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
603                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
604
605         iat_rva = read32 (ptr + 16);
606         if (iat_rva) {
607                 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
608                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
609
610                 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
611                         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));
612         }
613
614         if (name_rva) {
615                 name_rva = translate_rva (ctx, name_rva);
616                 g_assert (name_rva != INVALID_OFFSET);
617                 ptr = ctx->data + name_rva;
618         
619                 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
620                         char name[SIZE_OF_MSCOREE];
621                         memcpy (name, ptr, SIZE_OF_MSCOREE);
622                         name [SIZE_OF_MSCOREE - 1] = 0;
623                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
624                 }
625         }
626         
627         if (ilt_rva) {
628                 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
629                 CHECK_ERROR ();
630         }
631
632         if (iat_rva)
633                 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
634 }
635
636 static void
637 verify_resources_table (VerifyContext *ctx)
638 {
639         DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
640         guint32 offset;
641         guint16 named_entries, id_entries;
642         const char *ptr, *root, *end;
643
644         if (it.rva == 0)
645                 return;
646
647         if (it.size < 16)
648                 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));
649
650         offset = it.translated_offset;
651         root = ptr = ctx->data + offset;
652         end = root + it.size;
653
654         g_assert (offset != INVALID_OFFSET);
655
656         named_entries = read16 (ptr + 12);
657         id_entries = read16 (ptr + 14);
658
659         if ((named_entries + id_entries) * 8 + 16 > it.size)
660                 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));
661
662         /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource () 
663         if (named_entries || id_entries)
664                 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
665         */
666 }
667
668 /*----------nothing from here on can use data_directory---*/
669
670 static DataDirectory
671 get_data_dir (VerifyContext *ctx, int idx)
672 {
673         MonoCLIImageInfo *iinfo = ctx->image->image_info;
674         MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
675         DataDirectory res;
676
677         entry += idx;
678         res.rva = entry->rva;
679         res.size = entry->size;
680         res.translated_offset = translate_rva (ctx, res.rva);
681         return res;
682
683 }
684 static void
685 verify_cli_header (VerifyContext *ctx)
686 {
687         DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
688         guint32 offset;
689         const char *ptr;
690         int i;
691
692         if (it.rva == 0)
693                 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
694
695         if (it.size != 72)
696                 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
697
698         offset = it.translated_offset;
699         ptr = ctx->data + offset;
700
701         g_assert (offset != INVALID_OFFSET);
702
703         if (read16 (ptr) != 72)
704                 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
705
706         if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
707                 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
708
709
710         if (!read32 (ptr + 8) || !read32 (ptr + 12))
711                 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
712
713         if ((read32 (ptr + 16) & ~0x0001000B) != 0)
714                 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
715
716         ptr += 24;
717         for (i = 0; i < 6; ++i) {
718                 guint32 rva = read32 (ptr);
719                 guint32 size = read32 (ptr + 4);
720
721                 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
722                         ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
723
724                 ptr += 8;
725
726                 if (rva && i > 1)
727                         ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
728         }
729 }
730
731 static guint32
732 pad4 (guint32 offset)
733 {
734         if (offset & 0x3) //pad to the next 4 byte boundary
735                 offset = (offset & ~0x3) + 4;
736         return offset;
737 }
738
739 static void
740 verify_metadata_header (VerifyContext *ctx)
741 {
742         int i;
743         DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
744         guint32 offset;
745         const char *ptr;
746
747         offset = it.translated_offset;
748         ptr = ctx->data + offset;
749         g_assert (offset != INVALID_OFFSET);
750
751         //build a directory entry for the metadata root
752         ptr += 8;
753         it.rva = read32 (ptr);
754         ptr += 4;
755         it.size = read32 (ptr);
756         it.translated_offset = offset = translate_rva (ctx, it.rva);
757
758         ptr = ctx->data + offset;
759         g_assert (offset != INVALID_OFFSET);
760
761         if (it.size < 20)
762                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
763
764         if (read32 (ptr) != 0x424A5342)
765                 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
766
767         offset = pad4 (offset + 16 + read32 (ptr + 12));
768
769         if (!bounds_check_datadir (&it, offset, 4))
770                 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));
771
772         ptr = ctx->data + offset; //move to streams header 
773
774         if (read16 (ptr + 2) < 3)
775                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob"));
776
777         ptr += 4;
778         offset += 4;
779
780         for (i = 0; i < 5; ++i) {
781                 guint32 stream_off, stream_size;
782                 int string_size, stream_idx;
783
784                 if (!bounds_check_datadir (&it, offset, 8))
785                         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));
786
787                 stream_off = it.translated_offset + read32 (ptr);
788                 stream_size = read32 (ptr + 4);
789
790                 if (!bounds_check_datadir (&it,  stream_off, stream_size))
791                         ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
792
793                 ptr += 8;
794                 offset += 8;
795
796                 for (string_size = 0; string_size < 32; ++string_size) {
797                         if (!bounds_check_datadir (&it, offset++, 1))
798                                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
799                         if (!ptr [string_size])
800                                 break;
801                 }
802
803                 if (ptr [string_size])
804                         ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
805
806                 if (!strncmp ("#Strings", ptr, 9))
807                         stream_idx = STRINGS_STREAM;
808                 else if (!strncmp ("#US", ptr, 4))
809                         stream_idx = USER_STRINGS_STREAM;
810                 else if (!strncmp ("#Blob", ptr, 6))
811                         stream_idx = BLOB_STREAM;
812                 else if (!strncmp ("#GUID", ptr, 6))
813                         stream_idx = GUID_STREAM;
814                 else if (!strncmp ("#~", ptr, 3))
815                         stream_idx = TILDE_STREAM;
816                 else
817                         ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
818
819                 if (ctx->metadata_streams [stream_idx].offset != 0)
820                         ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
821
822                 ctx->metadata_streams [stream_idx].offset = stream_off;
823                 ctx->metadata_streams [stream_idx].size = stream_size;
824
825                 offset = pad4 (offset);
826                 ptr = ctx->data + offset;
827         }
828
829         if (!ctx->metadata_streams [TILDE_STREAM].size)
830                 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
831         if (!ctx->metadata_streams [GUID_STREAM].size)
832                 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
833         if (!ctx->metadata_streams [BLOB_STREAM].size)
834                 ADD_ERROR (ctx, g_strdup_printf ("Metadata blob stream missing"));
835                 
836 }
837
838 static void
839 verify_tables_schema (VerifyContext *ctx)
840 {
841         OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
842         unsigned offset = tables_area.offset;
843         const char *ptr = ctx->data + offset;
844         guint64 valid_tables;
845         guint32 count;
846         int i;
847
848         //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
849         if (tables_area.size < 24)
850                 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
851
852         //printf ("ptr %x %x\n", ptr[4], ptr[5]);
853         if (ptr [4] != 2 && ptr [4] != 1)
854                 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
855         if (ptr [5] != 0)
856                 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
857
858         if ((ptr [6] & ~0x7) != 0)
859                 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]));
860
861         valid_tables = read64 (ptr + 8);
862         count = 0;
863         for (i = 0; i < 64; ++i) {
864                 if (!(valid_tables & ((guint64)1 << i)))
865                         continue;
866
867                 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
868                   Unused: 0x1E 0x1F 0x2D-0x3F
869                   We don't care about the MS extensions.*/
870                 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
871                         ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
872                 if (i == 0x1E || i == 0x1F || i >= 0x2D)
873                         ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
874                 ++count;
875         }
876
877         if (tables_area.size < 24 + count * 4)
878                 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));
879         ptr += 24;
880
881         for (i = 0; i < 64; ++i) {
882                 if (valid_tables & ((guint64)1 << i)) {
883                         guint32 row_count = read32 (ptr);
884                         if (row_count > (1 << 24) - 1)
885                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
886                         ptr += 4;
887                 }
888         }
889 }
890
891 /*----------nothing from here on can use data_directory or metadata_streams ---*/
892
893 static guint32
894 get_col_offset (VerifyContext *ctx, int table, int column)
895 {
896         guint32 bitfield = ctx->image->tables [table].size_bitfield;
897         guint32 offset = 0;
898
899         while (column-- > 0)
900                 offset += mono_metadata_table_size (bitfield, column);
901
902         return offset;
903 }
904
905 static guint32
906 get_col_size (VerifyContext *ctx, int table, int column)
907 {
908         return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
909 }
910
911 static OffsetAndSize
912 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
913 {
914         OffsetAndSize res;
915         res.offset = header->data - ctx->data;
916         res.size = header->size;
917
918         return res;
919 }
920
921 static gboolean
922 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
923 {
924         OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
925         glong length;
926         const char *data = ctx->data + strings.offset;
927
928         if (offset >= strings.size)
929                 return FALSE;
930         if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing  
931                 return FALSE;
932
933         if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
934                 return FALSE;
935         return allow_empty || length > 0;
936 }
937
938 static gboolean
939 is_valid_string (VerifyContext *ctx, guint32 offset)
940 {
941         return is_valid_string_full (ctx, offset, TRUE);
942 }
943
944 static gboolean
945 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
946 {
947         return is_valid_string_full (ctx, offset, FALSE);
948 }
949
950 static gboolean
951 is_valid_guid (VerifyContext *ctx, guint32 offset)
952 {
953         OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
954         return guids.size >= 8 && guids.size - 8 >= offset;
955 }
956
957 static guint32
958 get_coded_index_token (int token_kind, guint32 coded_token)
959 {
960         guint32 bits = coded_index_desc [token_kind];
961         return coded_token >> bits;
962 }
963
964 static guint32
965 get_coded_index_table (int kind, guint32 coded_token)
966 {
967         guint32 idx, bits = coded_index_desc [kind];
968         kind += 2;
969         idx = coded_token & ((1 << bits) - 1);
970         return coded_index_desc [kind + idx];
971 }
972
973 static guint32
974 make_coded_token (int kind, guint32 table, guint32 table_idx)
975 {
976         guint32 bits = coded_index_desc [kind++];
977         guint32 tables = coded_index_desc [kind++];
978         guint32 i;
979         for (i = 0; i < tables; ++i) {
980                 if (coded_index_desc [kind++] == table)
981                         return ((table_idx + 1) << bits) | i; 
982         }
983         g_assert_not_reached ();
984         return -1;
985 }
986
987 static gboolean
988 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
989 {
990         guint32 bits = coded_index_desc [token_kind++];
991         guint32 table_count = coded_index_desc [token_kind++];
992         guint32 table = coded_token & ((1 << bits) - 1);
993         guint32 token = coded_token >> bits;
994
995         if (table >= table_count)
996                 return FALSE;
997
998         /*token_kind points to the first table idx*/
999         table = coded_index_desc [token_kind + table];
1000
1001         if (table == INVALID_TABLE)
1002                 return FALSE;
1003         return token <= ctx->image->tables [table].rows;
1004 }
1005
1006 typedef struct {
1007         guint32 token;
1008         guint32 col_size;
1009         guint32 col_offset;
1010         MonoTableInfo *table;
1011 } RowLocator;
1012
1013 static int
1014 token_locator (const void *a, const void *b)
1015 {
1016         RowLocator *loc = (RowLocator *)a;
1017         unsigned const char *row = (unsigned const char *)b;
1018         guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1019
1020         VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1021         return (int)loc->token - (int)token;
1022 }
1023
1024 static int
1025 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1026 {
1027         MonoTableInfo *tinfo = &ctx->image->tables [table];
1028         RowLocator locator;
1029         const char *res, *base;
1030         locator.token = coded_token;
1031         locator.col_offset = get_col_offset (ctx, table, column);
1032         locator.col_size = get_col_size (ctx, table, column);
1033         locator.table = tinfo;
1034
1035         base = tinfo->base;
1036
1037         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) );
1038         res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1039         if (!res)
1040                 return -1;
1041
1042         return (res - base) / tinfo->row_size;
1043 }
1044
1045 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1046 static const char*
1047 get_string_ptr (VerifyContext *ctx, guint offset)
1048 {
1049         return ctx->image->heap_strings.data + offset;
1050 }
1051
1052 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1053 static int
1054 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1055 {
1056         if (offset == 0)
1057                 return strcmp (str, "");
1058
1059         return strcmp (str, get_string_ptr (ctx, offset));
1060 }
1061
1062 static gboolean
1063 mono_verifier_is_corlib (MonoImage *image)
1064 {
1065         gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ? 
1066                         TRUE : mono_security_core_clr_is_platform_image (image);
1067
1068         return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1069 }
1070
1071 static gboolean
1072 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1073 {
1074         return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1075 }
1076
1077 static gboolean
1078 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1079 {
1080         unsigned char b;
1081         const unsigned char *ptr = (const unsigned char *)_ptr;
1082
1083         if (!available)
1084                 return FALSE;
1085
1086         b = *ptr;
1087         *value = *size = 0;
1088         
1089         if ((b & 0x80) == 0) {
1090                 *size = 1;
1091                 *value = b;
1092         } else if ((b & 0x40) == 0) {
1093                 if (available < 2)
1094                         return FALSE;
1095                 *size = 2;
1096                 *value = ((b & 0x3f) << 8 | ptr [1]);
1097         } else {
1098                 if (available < 4)
1099                         return FALSE;
1100                 *size = 4;
1101                 *value  = ((b & 0x1f) << 24) |
1102                         (ptr [1] << 16) |
1103                         (ptr [2] << 8) |
1104                         ptr [3];
1105         }
1106
1107         return TRUE;
1108 }
1109
1110 static gboolean
1111 decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
1112 {
1113         MonoStreamHeader blob = ctx->image->heap_blob;
1114         guint32 value, enc_size;
1115
1116         if (offset >= blob.size)
1117                 return FALSE;
1118
1119         if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1120                 return FALSE;
1121
1122         if (offset + enc_size + value < offset)
1123                 return FALSE;
1124
1125         if (offset + enc_size + value > blob.size)
1126                 return FALSE;
1127
1128         *size = value;
1129         *first_byte = blob.data + offset + enc_size;
1130         return TRUE;
1131 }
1132
1133 static gboolean
1134 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1135 {
1136         const char *ptr = *_ptr;
1137         if (ptr + size > limit)
1138                 return FALSE;
1139         switch (size) {
1140         case 1:
1141                 *dest = *((guint8*)ptr);
1142                 ++ptr;
1143                 break;
1144         case 2:
1145                 *dest = read16 (ptr);
1146                 ptr += 2;
1147                 break;
1148         case 4:
1149                 *dest = read32 (ptr);
1150                 ptr += 4;
1151                 break;
1152         }
1153         *_ptr = ptr;
1154         return TRUE;
1155 }
1156
1157 static gboolean
1158 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1159 {
1160         unsigned size = 0;
1161         const char *ptr = *_ptr;
1162         gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1163         *_ptr = ptr + size;
1164         return res;
1165 }
1166
1167 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1168 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1169 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1170 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1171
1172 static gboolean
1173 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1174
1175 static gboolean
1176 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1177
1178 static gboolean
1179 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1180 {
1181         const char *ptr = *_ptr;
1182         unsigned type = 0;
1183         unsigned token = 0;
1184
1185         while (TRUE) {
1186                 if (!safe_read8 (type, ptr, end))
1187                         FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1188         
1189                 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1190                         --ptr;
1191                         break;
1192                 }
1193         
1194                 if (!safe_read_cint (token, ptr, end))
1195                         FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1196         
1197                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1198                         FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1199         }
1200
1201         *_ptr = ptr;
1202         return TRUE;
1203 }
1204
1205 static gboolean
1206 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1207 {
1208         const char *ptr = *_ptr;
1209         unsigned val = 0;
1210         unsigned size, num, i;
1211
1212         if (!safe_read8 (val, ptr, end))
1213                 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1214
1215         if (val == 0)
1216                 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1217
1218         if (!safe_read_cint (size, ptr, end))
1219                 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1220
1221         for (i = 0; i < size; ++i) {
1222                 if (!safe_read_cint (num, ptr, end))
1223                         FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1224         }
1225
1226         if (!safe_read_cint (size, ptr, end))
1227                 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1228
1229         for (i = 0; i < size; ++i) {
1230                 if (!safe_read_cint (num, ptr, end))
1231                         FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1232         }
1233
1234         *_ptr = ptr;
1235         return TRUE;
1236 }
1237
1238 static gboolean
1239 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1240 {
1241         const char *ptr = *_ptr;
1242         unsigned type;
1243         unsigned count, token, i;
1244
1245         if (!safe_read8 (type, ptr, end))
1246                 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1247
1248         if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1249                 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1250
1251         if (!safe_read_cint (token, ptr, end))
1252                 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1253
1254         if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1255                 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1256
1257         if (!safe_read_cint (count, ptr, end))
1258                 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1259
1260         if (count == 0)
1261                 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1262
1263         for (i = 0; i < count; ++i) {
1264                 if (!parse_type (ctx, &ptr, end))
1265                         FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1266         }
1267         *_ptr = ptr;
1268         return TRUE;
1269 }
1270
1271 static gboolean
1272 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1273 {
1274         const char *ptr = *_ptr;
1275         unsigned type;
1276         unsigned token = 0;
1277
1278         if (!safe_read8 (type, ptr, end))
1279                 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1280
1281         if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1282                 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1283                 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1284                 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1285                 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1286
1287         switch (type) {
1288         case MONO_TYPE_PTR:
1289                 if (!parse_custom_mods (ctx, &ptr, end))
1290                         FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1291
1292                 if (!safe_read8 (type, ptr, end))
1293                         FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1294
1295                 if (type != MONO_TYPE_VOID) {
1296                         --ptr;
1297                         if (!parse_type (ctx, &ptr, end))
1298                                 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1299                 }
1300                 break;
1301
1302         case MONO_TYPE_VALUETYPE:
1303         case MONO_TYPE_CLASS:
1304                 if (!safe_read_cint (token, ptr, end))
1305                         FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1306         
1307                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1308                         FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1309                 break;
1310
1311         case MONO_TYPE_VAR:
1312         case MONO_TYPE_MVAR:
1313                 if (!safe_read_cint (token, ptr, end))
1314                         FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1315                 break;
1316
1317         case MONO_TYPE_ARRAY:
1318                 if (!parse_type (ctx, &ptr, end))
1319                         FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1320                 if (!parse_array_shape (ctx, &ptr, end))
1321                         FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1322                 break;
1323
1324         case MONO_TYPE_GENERICINST:
1325                 if (!parse_generic_inst (ctx, &ptr, end))
1326                         FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1327                 break;
1328
1329         case MONO_TYPE_FNPTR:
1330                 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1331                         FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1332                 break;
1333
1334         case MONO_TYPE_SZARRAY:
1335                 if (!parse_custom_mods (ctx, &ptr, end))
1336                         FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1337                 if (!parse_type (ctx, &ptr, end))
1338                         FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1339                 break;
1340         }
1341         *_ptr = ptr;
1342         return TRUE;
1343 }
1344
1345 static gboolean
1346 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1347 {
1348         const char *ptr;
1349         unsigned type = 0;
1350
1351         if (!parse_custom_mods (ctx, _ptr, end))
1352                 return FALSE;
1353
1354         ptr = *_ptr;
1355         if (!safe_read8 (type, ptr, end))
1356                 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1357
1358         if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1359                 *_ptr = ptr;
1360                 return TRUE;
1361         }
1362
1363         //it's a byref, update the cursor ptr
1364         if (type == MONO_TYPE_BYREF)
1365                 *_ptr = ptr;
1366
1367         return parse_type (ctx, _ptr, end);
1368 }
1369
1370 static gboolean
1371 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1372 {
1373         const char *ptr;
1374         unsigned type = 0;
1375
1376         if (!parse_custom_mods (ctx, _ptr, end))
1377                 return FALSE;
1378
1379         ptr = *_ptr;
1380         if (!safe_read8 (type, ptr, end))
1381                 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1382
1383         if (type == MONO_TYPE_TYPEDBYREF) {
1384                 *_ptr = ptr;
1385                 return TRUE;
1386         }
1387
1388         //it's a byref, update the cursor ptr
1389         if (type == MONO_TYPE_BYREF)
1390                 *_ptr = ptr;
1391
1392         return parse_type (ctx, _ptr, end);
1393 }
1394
1395 static gboolean
1396 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1397 {
1398         unsigned cconv = 0;
1399         unsigned param_count = 0, gparam_count = 0, type = 0, i;
1400         const char *ptr = *_ptr;
1401         gboolean saw_sentinel = FALSE;
1402
1403         if (!safe_read8 (cconv, ptr, end))
1404                 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1405
1406         if (cconv & 0x80)
1407                 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1408
1409         if (allow_unmanaged) {
1410                 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1411                         FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1412         } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1413                 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1414
1415         if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1416                 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1417
1418         if ((cconv & 0x10) && gparam_count == 0)
1419                 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1420
1421         if (allow_unmanaged && (cconv & 0x10))
1422                 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1423
1424         if (!safe_read_cint (param_count, ptr, end))
1425                 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1426
1427         if (!parse_return_type (ctx, &ptr, end))
1428                 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1429
1430         for (i = 0; i < param_count; ++i) {
1431                 if (allow_sentinel) {
1432                         if (!safe_read8 (type, ptr, end))
1433                                 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1434
1435                         if (type == MONO_TYPE_SENTINEL) {
1436                                 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1437                                         FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1438
1439                                 if (saw_sentinel)
1440                                         FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1441
1442                                 saw_sentinel = TRUE;
1443                         } else {
1444                                 --ptr;
1445                         }
1446                 }
1447
1448                 if (!parse_param (ctx, &ptr, end))
1449                         FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1450         }
1451
1452         *_ptr = ptr;
1453         return TRUE;
1454 }
1455
1456 static gboolean
1457 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1458 {
1459         unsigned sig = 0;
1460         unsigned param_count = 0, i;
1461         const char *ptr = *_ptr;
1462
1463         if (!safe_read8 (sig, ptr, end))
1464                 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1465
1466         if (sig != 0x08 && sig != 0x28)
1467                 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1468
1469         if (!safe_read_cint (param_count, ptr, end))
1470                 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1471
1472         if (!parse_custom_mods (ctx, &ptr, end))
1473                 return FALSE;
1474
1475         if (!parse_type (ctx, &ptr, end))
1476                 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1477
1478         for (i = 0; i < param_count; ++i) {
1479                 if (!parse_type (ctx, &ptr, end))
1480                         FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1481         }
1482
1483         *_ptr = ptr;
1484         return TRUE;
1485 }
1486
1487 static gboolean
1488 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1489 {
1490         const char *ptr = *_ptr;
1491         unsigned signature = 0;
1492
1493         if (!safe_read8 (signature, ptr, end))
1494                 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1495
1496         if (signature != 0x06)
1497                 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1498
1499         if (!parse_custom_mods (ctx, &ptr, end))
1500                 return FALSE;
1501
1502         if (safe_read8 (signature, ptr, end)) {
1503                 if (signature != MONO_TYPE_BYREF)
1504                         --ptr;
1505         }
1506         *_ptr = ptr;
1507
1508         return parse_type (ctx, _ptr, end);
1509 }
1510
1511 static gboolean
1512 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1513 {
1514         unsigned sig = 0;
1515         unsigned locals_count = 0, i;
1516         const char *ptr = *_ptr;        
1517
1518         if (!safe_read8 (sig, ptr, end))
1519                 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1520
1521         if (sig != 0x07)
1522                 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1523
1524         if (!safe_read_cint (locals_count, ptr, end))
1525                 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1526
1527         /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1528         if (locals_count == 0)
1529                 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1530         */
1531
1532         for (i = 0; i < locals_count; ++i) {
1533                 if (!safe_read8 (sig, ptr, end))
1534                         FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1535
1536                 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1537                         if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1538                                 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1539                         if (!safe_read8 (sig, ptr, end))
1540                                 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1541                 }
1542
1543                 if (sig == MONO_TYPE_BYREF) {
1544                         if (!safe_read8 (sig, ptr, end))
1545                                 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1546                         if (sig == MONO_TYPE_TYPEDBYREF)
1547                                 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1548                 }
1549
1550                 if (sig == MONO_TYPE_TYPEDBYREF)
1551                         continue;
1552
1553                 --ptr;
1554
1555                 if (!parse_type (ctx, &ptr, end))
1556                         FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1557         }
1558
1559         *_ptr = ptr;
1560         return TRUE;
1561 }
1562
1563 static gboolean
1564 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1565 {
1566         int size = 0;
1567         unsigned signature = 0;
1568         const char *ptr = NULL, *end;
1569
1570         if (!decode_signature_header (ctx, offset, &size, &ptr))
1571                 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1572         end = ptr + size;
1573
1574         if (!safe_read8 (signature, ptr, end))
1575                 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1576
1577         if (signature != 6)
1578                 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1579         --ptr;
1580
1581         return parse_field (ctx, &ptr, end);
1582 }
1583
1584 static gboolean
1585 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1586 {
1587         int size = 0;
1588         const char *ptr = NULL, *end;
1589
1590         if (!decode_signature_header (ctx, offset, &size, &ptr))
1591                 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1592         end = ptr + size;
1593
1594         return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1595 }
1596
1597 static gboolean
1598 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1599 {
1600         int size = 0;
1601         unsigned signature = 0;
1602         const char *ptr = NULL, *end;
1603
1604         if (!decode_signature_header (ctx, offset, &size, &ptr))
1605                 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1606         end = ptr + size;
1607
1608         if (!safe_read8 (signature, ptr, end))
1609                 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1610         --ptr;
1611
1612         if (signature == 0x06)
1613                 return parse_field (ctx, &ptr, end);
1614
1615         return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1616 }
1617
1618 static gboolean
1619 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1620 {
1621         int size = 0;
1622         unsigned prolog = 0;
1623         const char *ptr = NULL, *end;
1624
1625         if (!offset)
1626                 return TRUE;
1627
1628         if (!decode_signature_header (ctx, offset, &size, &ptr))
1629                 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1630         end = ptr + size;
1631
1632         if (!safe_read16 (prolog, ptr, end))
1633                 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1634
1635         if (prolog != 1)
1636                 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1637                 
1638         return TRUE;
1639 }
1640
1641 static gboolean
1642 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1643 {
1644         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1645         //TODO do proper verification
1646         return blob.size >= 1 && blob.size - 1 >= offset;
1647 }
1648
1649 static gboolean
1650 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1651 {
1652         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1653         //TODO do proper verification
1654         return blob.size >= 1 && blob.size - 1 >= offset;
1655 }
1656
1657 static gboolean
1658 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1659 {
1660         int size = 0;
1661         unsigned signature = 0;
1662         const char *ptr = NULL, *end;
1663
1664         if (!decode_signature_header (ctx, offset, &size, &ptr))
1665                 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1666         end = ptr + size;
1667
1668         if (!safe_read8 (signature, ptr, end))
1669                 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1670
1671         --ptr;
1672         if (signature == 0x07)
1673                 return parse_locals_signature (ctx, &ptr, end);
1674         return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1675 }
1676
1677 static gboolean
1678 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1679 {
1680         int size = 0;
1681         const char *ptr = NULL, *end;
1682
1683         if (!decode_signature_header (ctx, offset, &size, &ptr))
1684                 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
1685         end = ptr + size;
1686
1687         return parse_property_signature (ctx, &ptr, end);
1688 }
1689
1690 static gboolean
1691 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1692 {
1693         int size = 0;
1694         const char *ptr = NULL, *end;
1695         unsigned type = 0;
1696         
1697
1698         if (!decode_signature_header (ctx, offset, &size, &ptr))
1699                 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
1700         end = ptr + size;
1701
1702         if (!parse_custom_mods (ctx, &ptr, end))
1703                 return FALSE;
1704
1705         if (!safe_read8 (type, ptr, end))
1706                 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
1707
1708         if (type == MONO_TYPE_BYREF) {
1709                 if (!safe_read8 (type, ptr, end)) 
1710                         FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
1711                 if (type == MONO_TYPE_TYPEDBYREF)
1712                         FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
1713         }
1714         
1715         if (type == MONO_TYPE_TYPEDBYREF)
1716                 return TRUE;
1717
1718         --ptr;
1719         return parse_type (ctx, &ptr, end);
1720 }
1721
1722 static gboolean
1723 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1724 {
1725         int size = 0;
1726         const char *ptr = NULL, *end;
1727         unsigned type = 0;
1728         unsigned count = 0, i;
1729
1730         if (!decode_signature_header (ctx, offset, &size, &ptr))
1731                 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
1732         end = ptr + size;
1733
1734         if (!safe_read8 (type, ptr, end))
1735                 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
1736
1737         if (type != 0x0A)
1738                 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
1739
1740         if (!safe_read_cint (count, ptr, end))
1741                 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
1742
1743         if (!count)
1744                 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
1745
1746         for (i = 0; i < count; ++i) {
1747                 if (!parse_type (ctx, &ptr, end))
1748                         FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
1749         }
1750         return TRUE;
1751 }
1752
1753 static gboolean
1754 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
1755 {
1756         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1757         guint32 entry_size, bytes;
1758
1759         if (blob.size < offset)
1760                 return FALSE;
1761
1762         if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1763                 return FALSE;
1764
1765         if (entry_size < minsize)
1766                 return FALSE;
1767
1768         if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
1769                 return FALSE;
1770         entry_size += bytes;
1771
1772         return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
1773 }
1774
1775 static gboolean
1776 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1777 {
1778         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1779         guint32 size, entry_size, bytes;
1780
1781         if (blob.size < offset)
1782                 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
1783         
1784         if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1785                 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
1786
1787         if (type == MONO_TYPE_STRING) {
1788                 //String is encoded as: compressed_int:len len *bytes
1789                 offset += bytes;
1790
1791                 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
1792                         FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));  
1793
1794                 return TRUE;
1795         }
1796
1797         switch (type) {
1798         case MONO_TYPE_BOOLEAN:
1799         case MONO_TYPE_I1:
1800         case MONO_TYPE_U1:
1801                 size = 1;
1802                 break;
1803         case MONO_TYPE_CHAR:
1804         case MONO_TYPE_I2:
1805         case MONO_TYPE_U2:
1806                 size = 2;
1807                 break;
1808         case MONO_TYPE_I4:
1809         case MONO_TYPE_U4:
1810         case MONO_TYPE_R4:
1811         case MONO_TYPE_CLASS:
1812                 size = 4;
1813                 break;
1814
1815         case MONO_TYPE_I8:
1816         case MONO_TYPE_U8:
1817         case MONO_TYPE_R8:
1818                 size = 8;
1819                 break;
1820         default:
1821                 g_assert_not_reached ();
1822         }
1823
1824         if (size != entry_size)
1825                 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
1826
1827         offset += bytes;
1828
1829         if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
1830                 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
1831
1832         if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
1833                 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
1834         return TRUE;
1835 }
1836
1837 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
1838 //only 0x01, 0x40 and 0x80 are allowed
1839 #define SECTION_HEADER_INVALID_FLAGS 0x3E
1840
1841 static gboolean
1842 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1843 {
1844         unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
1845         unsigned header = 0;
1846         unsigned fat_header = 0, size = 0, max_stack;
1847         const char *ptr = NULL, *end;
1848
1849         if (offset == INVALID_ADDRESS)
1850                 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
1851
1852         ptr = ctx->data + offset;
1853         end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
1854
1855         if (!safe_read8 (header, ptr, end))
1856                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
1857
1858         switch (header & 0x3) {
1859         case 0:
1860         case 1:
1861                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
1862         case 2:
1863                 header >>= 2;
1864                 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end)) 
1865                         FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
1866                 return TRUE;
1867         }
1868         //FAT HEADER
1869         --ptr;
1870         if (!safe_read16 (fat_header, ptr, end))
1871                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
1872
1873         size = (fat_header >> 12) & 0xF;
1874         if (size != 3)
1875                 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
1876
1877         if (!safe_read16 (max_stack, ptr, end))
1878                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
1879
1880         if (!safe_read32 (code_size, ptr, end))
1881                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
1882
1883         if (!safe_read32 (local_vars_tok, ptr, end))
1884                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
1885
1886         if (local_vars_tok) {
1887                 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
1888                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
1889                 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)   
1890                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
1891         }
1892
1893         if (fat_header & FAT_HEADER_INVALID_FLAGS)
1894                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
1895
1896         if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
1897                 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
1898
1899         if (!(fat_header & 0x08))
1900                 return TRUE;
1901
1902         ptr += code_size;
1903
1904         do {
1905                 unsigned section_header = 0, section_size = 0;
1906                 gboolean is_fat;
1907
1908                 ptr = dword_align (ptr);
1909                 if (!safe_read32 (section_header, ptr, end))
1910                         FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
1911
1912                 if (section_header & SECTION_HEADER_INVALID_FLAGS)
1913                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
1914                         
1915                 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
1916                 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
1917
1918                 if (section_size < 4)
1919                         FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
1920
1921                 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
1922                         FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
1923
1924                 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
1925                         guint32 i, clauses = section_size / (is_fat ? 24 : 12);
1926                         /*
1927                                 LAMEIMPL: MS emits section_size without accounting for header size.
1928                                 Mono does as the spec says. section_size is header + section
1929                                 MS's peverify happily accepts both. 
1930                         */
1931                         if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
1932                                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid EH section size %d, it's not of the expected size %d", section_size, clauses * (is_fat ? 24 : 12)));
1933
1934                         /* only verify the class token is verified as the rest is done by the IL verifier*/
1935                         for (i = 0; i < clauses; ++i) {
1936                                 unsigned flags = *(unsigned char*)ptr;
1937                                 unsigned class_token = 0;
1938                                 ptr += (is_fat ? 20 : 8);
1939                                 if (!safe_read32 (class_token, ptr, end))
1940                                         FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
1941                                 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
1942                                         guint table = mono_metadata_token_table (class_token);
1943                                         if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
1944                                                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
1945                                         if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
1946                                                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
1947                                 }
1948                         }
1949                 }
1950
1951                 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
1952                         break;
1953         } while (1);
1954         return TRUE;
1955 }
1956
1957 static void
1958 verify_module_table (VerifyContext *ctx)
1959 {
1960         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1961         guint32 data [MONO_MODULE_SIZE];
1962
1963         if (table->rows != 1)
1964                 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1965
1966         mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1967
1968         if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1969                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1970
1971         if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1972                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1973
1974         if (data [MONO_MODULE_ENC] != 0)
1975                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1976
1977         if (data [MONO_MODULE_ENCBASE] != 0)
1978                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1979 }
1980
1981 static void
1982 verify_typeref_table (VerifyContext *ctx)
1983 {
1984         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1985         guint32 data [MONO_TYPEREF_SIZE];
1986         int i;
1987
1988         for (i = 0; i < table->rows; ++i) {
1989                 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1990                 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1991                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1992                 
1993                 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1994                         ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1995
1996                 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1997                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1998
1999                 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2000                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
2001         }
2002 }
2003
2004 /*bits 9,11,14,15,19,21,24-31 */
2005 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2006 static void
2007 verify_typedef_table (VerifyContext *ctx)
2008 {
2009         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2010         guint32 data [MONO_TYPEDEF_SIZE];
2011         guint32 fieldlist = 1, methodlist = 1;
2012         int i;
2013
2014         if (table->rows == 0)
2015                 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2016
2017         for (i = 0; i < table->rows; ++i) {
2018                 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2019                 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2020                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2021
2022                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2023                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2024
2025                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2026                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2027
2028                 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2029                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2030
2031                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2032                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2033
2034                 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2035                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2036
2037                 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2038                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2039
2040                 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2041                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2042
2043                 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2044                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2045
2046                 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2047                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2048
2049                 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2050                         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));
2051
2052                 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2053                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2054
2055                 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2056                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2057
2058                 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2059                         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));
2060
2061                 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2062                 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2063         }
2064 }
2065
2066 static void
2067 verify_typedef_table_full (VerifyContext *ctx)
2068 {
2069         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2070         guint32 data [MONO_TYPEDEF_SIZE];
2071         int i;
2072
2073         if (table->rows == 0)
2074                 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2075
2076         for (i = 0; i < table->rows; ++i) {
2077                 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2078
2079                 if (i == 0) {
2080                         if (data [MONO_TYPEDEF_EXTENDS] != 0)
2081                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2082                         continue;
2083                 }
2084
2085                 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2086                         if (data [MONO_TYPEDEF_EXTENDS])
2087                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2088                 } else {
2089                         gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2090                         gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2091
2092                         if (is_sys_obj) {
2093                                 if (has_parent)
2094                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2095                         } else {
2096                                 if (!has_parent) {
2097                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2098                                 }
2099                         }
2100                 }
2101         }
2102 }
2103
2104 /*bits 3,11,14 */
2105 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2106 static void
2107 verify_field_table (VerifyContext *ctx)
2108 {
2109         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2110         guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2111         int i;
2112
2113         module_field_list = (guint32)-1;
2114         if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2115                 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2116                 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2117         }
2118         
2119         for (i = 0; i < table->rows; ++i) {
2120                 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2121                 flags = data [MONO_FIELD_FLAGS];
2122
2123                 if (flags & INVALID_FIELD_FLAG_BITS)
2124                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2125
2126                 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)         
2127                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2128
2129                 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2130                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2131
2132                 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2133                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2134
2135                 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2136                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2137
2138                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2139                                 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2140                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2141
2142                 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2143                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2144                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2145
2146                 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2147                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2148                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2149
2150                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2151                                 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2152                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2153
2154                 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2155                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2156
2157                 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2158                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2159
2160                 //TODO verify contant flag
2161
2162                 if (i + 1 < module_field_list) {
2163                         guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2164                         if (!(flags & FIELD_ATTRIBUTE_STATIC))
2165                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2166                         if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2167                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2168                 }
2169         }
2170 }
2171
2172 static void
2173 verify_field_table_full (VerifyContext *ctx)
2174 {
2175         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2176         guint32 data [MONO_FIELD_SIZE];
2177         int i;
2178         
2179         for (i = 0; i < table->rows; ++i) {
2180                 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2181
2182                 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2183                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2184         }
2185 }
2186
2187 /*bits 6,8,9,10,11,13,14,15*/
2188 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2189 static void
2190 verify_method_table (VerifyContext *ctx)
2191 {
2192         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2193         guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2194         guint32 paramlist = 1;
2195         gboolean is_ctor, is_cctor;
2196         const char *name;
2197         int i;
2198
2199         module_method_list = (guint32)-1;
2200         if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2201                 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2202                 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2203         }
2204
2205         for (i = 0; i < table->rows; ++i) {
2206                 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2207                 rva = data [MONO_METHOD_RVA];
2208                 implflags = data [MONO_METHOD_IMPLFLAGS];
2209                 flags = data [MONO_METHOD_FLAGS];
2210                 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2211                 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2212                 
2213
2214                 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2215                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2216
2217                 if (access == 0x7)
2218                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2219
2220                 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2221                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2222
2223                 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2224                 is_ctor = !strcmp (".ctor", name);
2225                 is_cctor = !strcmp (".cctor", name);
2226
2227                 if ((is_ctor || is_cctor) &&
2228                         search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2229                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2230
2231                 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2232                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2233                 
2234                 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2235                         if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2236                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2237                         if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2238                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2239                 }
2240
2241                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2242                         ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2243
2244                 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2245                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2246
2247                 //XXX no checks against cas stuff 10,11,12,13)
2248
2249                 //TODO check iface with .ctor (15,16)
2250
2251                 if (i + 1 < module_method_list) {
2252                         if (!(flags & METHOD_ATTRIBUTE_STATIC))
2253                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2254                         if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2255                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2256                         if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2257                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2258                 }
2259
2260                 //TODO check valuetype for synchronized
2261
2262                 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2263                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2264
2265                 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2266                         if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2267                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2268                         if (!(flags & METHOD_ATTRIBUTE_STATIC))
2269                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2270                 }
2271
2272                 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && 
2273                                 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2274                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2275
2276                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2277                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2278
2279                 //TODO check signature contents
2280
2281                 if (rva) {
2282                         if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2283                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2284                         if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2285                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2286                 } else {
2287                         if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2288                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2289                 }
2290
2291                 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2292                         if (rva)
2293                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2294                         if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2295                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2296                 }
2297                 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2298                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2299
2300                 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2301                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2302
2303                 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2304                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2305
2306                 if (data [MONO_METHOD_PARAMLIST] == 0)
2307                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2308
2309                 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2310                         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));
2311
2312                 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2313                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2314
2315                 paramlist = data [MONO_METHOD_PARAMLIST];
2316
2317         }
2318 }
2319
2320 static void
2321 verify_method_table_full (VerifyContext *ctx)
2322 {
2323         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2324         guint32 data [MONO_METHOD_SIZE], rva;
2325         int i;
2326
2327         for (i = 0; i < table->rows; ++i) {
2328                 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2329                 rva = data [MONO_METHOD_RVA];
2330
2331                 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2332                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2333
2334                 if (rva && !is_valid_method_header (ctx, rva))
2335                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2336         }
2337 }
2338
2339 static guint32
2340 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2341 {
2342         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2343         guint32 row = *current_method;
2344         guint32 paramlist, tmp;
2345
2346
2347         paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2348         while (row < table->rows) {
2349                 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2350                 if (tmp > paramlist) {
2351                         *current_method = row;
2352                         return tmp - paramlist;
2353                 }
2354                 ++row;
2355         }
2356
2357         /*no more methods, all params apply to the last one*/
2358         *current_method = table->rows;
2359         return (guint32)-1;
2360 }
2361
2362
2363 #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))
2364 static void
2365 verify_param_table (VerifyContext *ctx)
2366 {
2367         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2368         guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2369         gboolean first_param = TRUE;
2370         int i;
2371
2372         if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2373                 if (table->rows > 0)
2374                         ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2375                 return;
2376         }
2377         
2378         remaining_params = get_next_param_count (ctx, &current_method);
2379
2380         for (i = 0; i < table->rows; ++i) {
2381                 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2382                 flags = data [MONO_PARAM_FLAGS];
2383
2384                 if (flags & INVALID_PARAM_FLAGS_BITS)
2385                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2386
2387                 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2388                         if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2389                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2390                 } else {
2391                         if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2392                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2393                 }
2394
2395                 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)
2396                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2397
2398                 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2399                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2400
2401                 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2402                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2403
2404                 first_param = FALSE;
2405                 sequence = data [MONO_PARAM_SEQUENCE];
2406                 if (--remaining_params == 0) {
2407                         remaining_params = get_next_param_count (ctx, &current_method);
2408                         first_param = TRUE;
2409                 }
2410         }
2411 }
2412
2413 static void
2414 verify_interfaceimpl_table (VerifyContext *ctx)
2415 {
2416         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2417         guint32 data [MONO_INTERFACEIMPL_SIZE];
2418         int i;
2419
2420         for (i = 0; i < table->rows; ++i) {
2421                 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2422                 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2423                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2424
2425                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2426                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2427
2428                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2429                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2430         }
2431 }
2432
2433 static void
2434 verify_memberref_table (VerifyContext *ctx)
2435 {
2436         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2437         guint32 data [MONO_MEMBERREF_SIZE];
2438         int i;
2439
2440         for (i = 0; i < table->rows; ++i) {
2441                 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2442
2443                 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2444                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2445
2446                 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2447                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2448
2449                 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2450                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2451
2452                 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2453                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2454         }
2455 }
2456
2457
2458 static void
2459 verify_memberref_table_full (VerifyContext *ctx)
2460 {
2461         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2462         guint32 data [MONO_MEMBERREF_SIZE];
2463         int i;
2464
2465         for (i = 0; i < table->rows; ++i) {
2466                 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2467
2468                 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2469                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field  0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2470         }
2471 }
2472
2473 static void
2474 verify_constant_table (VerifyContext *ctx)
2475 {
2476         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2477         guint32 data [MONO_CONSTANT_SIZE], type;
2478         int i;
2479
2480         for (i = 0; i < table->rows; ++i) {
2481                 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2482                 type = data [MONO_CONSTANT_TYPE];
2483
2484                 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2485                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2486
2487                 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2488                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2489
2490                 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2491                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2492
2493                 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2494                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2495         }
2496 }
2497
2498 static void
2499 verify_cattr_table (VerifyContext *ctx)
2500 {
2501         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2502         guint32 data [MONO_CUSTOM_ATTR_SIZE];
2503         int i;
2504
2505         for (i = 0; i < table->rows; ++i) {
2506                 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2507
2508                 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2509                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2510
2511                 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2512                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2513
2514                 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2515                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2516         }
2517 }
2518
2519 static void
2520 verify_cattr_table_full (VerifyContext *ctx)
2521 {
2522         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2523         guint32 data [MONO_CUSTOM_ATTR_SIZE];
2524         int i;
2525
2526         for (i = 0; i < table->rows; ++i) {
2527                 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2528
2529                 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2530                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2531         }
2532 }
2533
2534 static void
2535 verify_field_marshal_table (VerifyContext *ctx)
2536 {
2537         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2538         guint32 data [MONO_FIELD_MARSHAL_SIZE];
2539         int i;
2540
2541         for (i = 0; i < table->rows; ++i) {
2542                 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2543
2544                 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2545                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2546
2547                 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2548                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2549
2550                 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2551                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2552
2553                 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2554                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2555         }
2556 }
2557
2558 static void
2559 verify_field_marshal_table_full (VerifyContext *ctx)
2560 {
2561         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2562         guint32 data [MONO_FIELD_MARSHAL_SIZE];
2563         int i;
2564
2565         for (i = 0; i < table->rows; ++i) {
2566                 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2567
2568                 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2569                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2570         }
2571 }
2572
2573 static void
2574 verify_decl_security_table (VerifyContext *ctx)
2575 {
2576         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2577         guint32 data [MONO_DECL_SECURITY_SIZE];
2578         int i;
2579
2580         for (i = 0; i < table->rows; ++i) {
2581                 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2582
2583                 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2584                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2585
2586                 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2587                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2588
2589                 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2590                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2591         }
2592 }
2593
2594 static void
2595 verify_decl_security_table_full (VerifyContext *ctx)
2596 {
2597         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2598         guint32 data [MONO_DECL_SECURITY_SIZE];
2599         int i;
2600
2601         for (i = 0; i < table->rows; ++i) {
2602                 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2603
2604                 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2605                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2606         }
2607 }
2608
2609 static void
2610 verify_class_layout_table (VerifyContext *ctx)
2611 {
2612         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2613         guint32 data [MONO_CLASS_LAYOUT_SIZE];
2614         int i;
2615
2616         for (i = 0; i < table->rows; ++i) {
2617                 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2618
2619                 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2620                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2621
2622                 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2623                 case 0:
2624                 case 1:
2625                 case 2:
2626                 case 4:
2627                 case 8:
2628                 case 16:
2629                 case 32:
2630                 case 64:
2631                 case 128:
2632                         break;
2633                 default:
2634                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2635                 }
2636         }
2637 }
2638
2639 static void
2640 verify_field_layout_table (VerifyContext *ctx)
2641 {
2642         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2643         guint32 data [MONO_FIELD_LAYOUT_SIZE];
2644         int i;
2645
2646         for (i = 0; i < table->rows; ++i) {
2647                 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2648
2649                 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2650                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2651         }
2652 }
2653
2654 static void
2655 verify_standalonesig_table (VerifyContext *ctx)
2656 {
2657         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2658         guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2659         int i;
2660
2661         for (i = 0; i < table->rows; ++i) {
2662                 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2663
2664                 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
2665                         ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2666         }
2667 }
2668
2669 static void
2670 verify_standalonesig_table_full (VerifyContext *ctx)
2671 {
2672         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2673         guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2674         int i;
2675
2676         for (i = 0; i < table->rows; ++i) {
2677                 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2678
2679                 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2680                         ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2681         }
2682 }
2683
2684 static void
2685 verify_eventmap_table (VerifyContext *ctx)
2686 {
2687         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2688         guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2689         int i;
2690
2691         for (i = 0; i < table->rows; ++i) {
2692                 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2693
2694                 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2695                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2696
2697                 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2698                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2699
2700                 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2701         }
2702 }
2703
2704 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2705 static void
2706 verify_event_table (VerifyContext *ctx)
2707 {
2708         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2709         guint32 data [MONO_EVENT_SIZE];
2710         int i;
2711
2712         for (i = 0; i < table->rows; ++i) {
2713                 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2714
2715                 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2716                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2717
2718                 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2719                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2720
2721                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2722                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2723         }
2724 }
2725
2726 static void
2727 verify_event_table_full (VerifyContext *ctx)
2728 {
2729         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2730         MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2731         guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2732         gboolean found_add, found_remove;
2733         int i, idx;
2734
2735         for (i = 0; i < table->rows; ++i) {
2736                 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2737
2738                 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2739                 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2740                 if (idx == -1)
2741                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2742
2743                 //first we move to the first row for this event
2744                 while (idx > 0) {
2745                         if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2746                                 break;
2747                         --idx;
2748                 }
2749                 //now move forward looking for AddOn and RemoveOn rows
2750                 found_add = found_remove = FALSE;
2751                 while (idx < sema_table->rows) {
2752                         mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2753                         if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2754                                 break;
2755                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2756                                 found_add = TRUE;
2757                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2758                                 found_remove = TRUE;
2759                         if (found_add && found_remove)
2760                                 break;
2761                         ++idx;
2762                 }
2763
2764                 if (!found_add)
2765                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2766                 if (!found_remove)
2767                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2768         }
2769 }
2770
2771 static void
2772 verify_propertymap_table (VerifyContext *ctx)
2773 {
2774         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2775         guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2776         int i;
2777
2778         for (i = 0; i < table->rows; ++i) {
2779                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2780
2781                 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2782                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2783
2784                 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2785                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2786
2787                 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2788         }
2789 }
2790
2791 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2792 static void
2793 verify_property_table (VerifyContext *ctx)
2794 {
2795         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2796         guint32 data [MONO_PROPERTY_SIZE];
2797         int i;
2798
2799         for (i = 0; i < table->rows; ++i) {
2800                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2801
2802                 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2803                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2804
2805                 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2806                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2807
2808                 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2809                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2810
2811                 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2812                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2813                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2814
2815         }
2816 }
2817
2818 static void
2819 verify_methodimpl_table (VerifyContext *ctx)
2820 {
2821         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2822         guint32 data [MONO_METHODIMPL_SIZE];
2823         int i;
2824
2825         for (i = 0; i < table->rows; ++i) {
2826                 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2827
2828                 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2829                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2830                         
2831                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2832                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2833                 
2834                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2835                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2836
2837                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2838                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2839                 
2840                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2841                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2842         }
2843 }
2844
2845 static void
2846 verify_moduleref_table (VerifyContext *ctx)
2847 {
2848         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2849         guint32 data [MONO_MODULEREF_SIZE];
2850         int i;
2851
2852         for (i = 0; i < table->rows; ++i) {
2853                 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2854
2855                 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2856                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2857         }
2858 }
2859
2860 static void
2861 verify_typespec_table (VerifyContext *ctx)
2862 {
2863         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2864         guint32 data [MONO_TYPESPEC_SIZE];
2865         int i;
2866
2867         for (i = 0; i < table->rows; ++i) {
2868                 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2869
2870                 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
2871                         ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2872         }
2873 }
2874
2875 static void
2876 verify_typespec_table_full (VerifyContext *ctx)
2877 {
2878         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2879         guint32 data [MONO_TYPESPEC_SIZE];
2880         int i;
2881
2882         for (i = 0; i < table->rows; ++i) {
2883                 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2884
2885                 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2886                         ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2887         }
2888 }
2889
2890 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
2891 static void
2892 verify_implmap_table (VerifyContext *ctx)
2893 {
2894         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2895         guint32 data [MONO_IMPLMAP_SIZE], cconv;
2896         int i;
2897
2898         for (i = 0; i < table->rows; ++i) {
2899                 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2900
2901                 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2902                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2903
2904                 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2905                 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2906                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2907
2908                 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2909                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2910
2911                 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2912                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2913
2914                 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2915                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2916
2917                 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2918                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2919
2920                 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
2921                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2922         }
2923 }
2924
2925 static void
2926 verify_fieldrva_table (VerifyContext *ctx)
2927 {
2928         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2929         guint32 data [MONO_FIELD_RVA_SIZE];
2930         int i;
2931
2932         for (i = 0; i < table->rows; ++i) {
2933                 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2934
2935                 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2936                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2937
2938                 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2939                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2940         }
2941 }
2942
2943 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
2944 static void
2945 verify_assembly_table (VerifyContext *ctx)
2946 {
2947         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2948         guint32 data [MONO_ASSEMBLY_SIZE], hash;
2949         int i;
2950
2951         if (table->rows > 1)
2952                 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2953
2954         for (i = 0; i < table->rows; ++i) {
2955                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2956
2957                 hash = data [MONO_ASSEMBLY_HASH_ALG];
2958                 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2959                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2960
2961                 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2962                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2963
2964                 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
2965                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2966
2967                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2968                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2969
2970                 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2971                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2972         }
2973 }
2974
2975 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2976 static void
2977 verify_assemblyref_table (VerifyContext *ctx)
2978 {
2979         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2980         guint32 data [MONO_ASSEMBLYREF_SIZE];
2981         int i;
2982
2983         for (i = 0; i < table->rows; ++i) {
2984                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2985
2986                 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2987                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2988
2989                 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
2990                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2991
2992                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2993                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
2994
2995                 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
2996                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
2997
2998                 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
2999                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3000         }
3001 }
3002
3003 #define INVALID_FILE_FLAGS_BITS ~(1)
3004 static void
3005 verify_file_table (VerifyContext *ctx)
3006 {
3007         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3008         guint32 data [MONO_FILE_SIZE];
3009         int i;
3010
3011         for (i = 0; i < table->rows; ++i) {
3012                 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3013                 
3014                 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3015                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3016
3017                 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3018                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3019
3020                 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3021                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3022         }
3023 }
3024
3025 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3026 static void
3027 verify_exportedtype_table (VerifyContext *ctx)
3028 {
3029         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3030         guint32 data [MONO_EXP_TYPE_SIZE];
3031         int i;
3032
3033         for (i = 0; i < table->rows; ++i) {
3034                 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3035                 
3036                 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3037                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3038
3039                 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3040                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3041
3042                 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3043                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3044
3045                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3046                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3047
3048                 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3049                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3050
3051                 /*nested type can't have a namespace*/
3052                 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3053                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3054         }
3055 }
3056
3057 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3058 static void
3059 verify_manifest_resource_table (VerifyContext *ctx)
3060 {
3061         MonoCLIImageInfo *iinfo = ctx->image->image_info;
3062         MonoCLIHeader *ch = &iinfo->cli_cli_header;
3063         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3064         guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3065         int i;
3066
3067         resources_size = ch->ch_resources.size;
3068
3069         for (i = 0; i < table->rows; ++i) {
3070                 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3071
3072                 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3073                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3074
3075                 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3076                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3077
3078                 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3079                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3080
3081                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3082                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3083
3084                 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3085                 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3086
3087                 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3088                         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])));
3089
3090                 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3091                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3092
3093                 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3094                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3095         }
3096 }
3097
3098 static void
3099 verify_nested_class_table (VerifyContext *ctx)
3100 {
3101         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3102         guint32 data [MONO_NESTED_CLASS_SIZE];
3103         int i;
3104
3105         for (i = 0; i < table->rows; ++i) {
3106                 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3107
3108                 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3109                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3110                 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3111                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3112                 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3113                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass  and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3114         }
3115 }
3116
3117 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3118 static void
3119 verify_generic_param_table (VerifyContext *ctx)
3120 {
3121         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3122         guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3123         int i, param_number = 0;
3124
3125         for (i = 0; i < table->rows; ++i) {
3126                 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3127
3128                 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3129                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3130
3131                 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3132                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3133
3134                 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3135                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3136
3137                 token = data [MONO_GENERICPARAM_OWNER];
3138
3139                 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3140                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3141
3142                 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3143                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3144
3145                 if (token != last_token) {
3146                         param_number = 0;
3147                         last_token = token;
3148                 }
3149
3150                 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3151                         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));
3152
3153                 ++param_number;
3154         }
3155 }
3156
3157 static void
3158 verify_method_spec_table (VerifyContext *ctx)
3159 {
3160         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3161         guint32 data [MONO_METHODSPEC_SIZE];
3162         int i;
3163
3164         for (i = 0; i < table->rows; ++i) {
3165                 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3166
3167                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3168                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3169
3170                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3171                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3172
3173                 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3174                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3175         }
3176 }
3177
3178 static void
3179 verify_method_spec_table_full (VerifyContext *ctx)
3180 {
3181         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3182         guint32 data [MONO_METHODSPEC_SIZE];
3183         int i;
3184
3185         for (i = 0; i < table->rows; ++i) {
3186                 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3187
3188                 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3189                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3190         }
3191 }
3192
3193 static void
3194 verify_generic_param_constraint_table (VerifyContext *ctx)
3195 {
3196         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3197         guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3198         int i;
3199
3200         for (i = 0; i < table->rows; ++i) {
3201                 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3202
3203                 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3204                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3205
3206                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3207                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3208
3209                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3210                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3211         }
3212 }
3213
3214 static void
3215 verify_tables_data (VerifyContext *ctx)
3216 {
3217         OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3218         guint32 size = 0, tables_offset;
3219         int i;
3220
3221         for (i = 0; i < 0x2D; ++i) {
3222                 MonoTableInfo *table = &ctx->image->tables [i];
3223                 guint32 tmp_size;
3224                 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3225                 if (tmp_size < size) {
3226                         size = 0;
3227                         break;
3228                 }
3229                 size = tmp_size;                        
3230         }
3231
3232         if (size == 0)
3233                 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3234
3235         tables_offset = ctx->image->tables_base - ctx->data;
3236         if (!bounds_check_offset (&tables_area, tables_offset, size))
3237                 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)));
3238
3239         verify_module_table (ctx);
3240         CHECK_ERROR ();
3241         verify_typeref_table (ctx);
3242         CHECK_ERROR ();
3243         verify_typedef_table (ctx);
3244         CHECK_ERROR ();
3245         verify_field_table (ctx);
3246         CHECK_ERROR ();
3247         verify_method_table (ctx);
3248         CHECK_ERROR ();
3249         verify_param_table (ctx);
3250         CHECK_ERROR ();
3251         verify_interfaceimpl_table (ctx);
3252         CHECK_ERROR ();
3253         verify_memberref_table (ctx);
3254         CHECK_ERROR ();
3255         verify_constant_table (ctx);
3256         CHECK_ERROR ();
3257         verify_cattr_table (ctx);
3258         CHECK_ERROR ();
3259         verify_field_marshal_table (ctx);
3260         CHECK_ERROR ();
3261         verify_decl_security_table (ctx);
3262         CHECK_ERROR ();
3263         verify_class_layout_table (ctx);
3264         CHECK_ERROR ();
3265         verify_field_layout_table (ctx);
3266         CHECK_ERROR ();
3267         verify_standalonesig_table (ctx);
3268         CHECK_ERROR ();
3269         verify_eventmap_table (ctx);
3270         CHECK_ERROR ();
3271         verify_event_table (ctx);
3272         CHECK_ERROR ();
3273         verify_propertymap_table (ctx);
3274         CHECK_ERROR ();
3275         verify_property_table (ctx);
3276         CHECK_ERROR ();
3277         verify_methodimpl_table (ctx);
3278         CHECK_ERROR ();
3279         verify_moduleref_table (ctx);
3280         CHECK_ERROR ();
3281         verify_typespec_table (ctx);
3282         CHECK_ERROR ();
3283         verify_implmap_table (ctx);
3284         CHECK_ERROR ();
3285         verify_fieldrva_table (ctx);
3286         CHECK_ERROR ();
3287         verify_assembly_table (ctx);
3288         CHECK_ERROR ();
3289         verify_assemblyref_table (ctx);
3290         CHECK_ERROR ();
3291         verify_file_table (ctx);
3292         CHECK_ERROR ();
3293         verify_exportedtype_table (ctx);
3294         CHECK_ERROR ();
3295         verify_manifest_resource_table (ctx);
3296         CHECK_ERROR ();
3297         verify_nested_class_table (ctx);
3298         CHECK_ERROR ();
3299         verify_generic_param_table (ctx);
3300         CHECK_ERROR ();
3301         verify_method_spec_table (ctx);
3302         CHECK_ERROR ();
3303         verify_generic_param_constraint_table (ctx);
3304 }
3305
3306 static void
3307 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
3308 {
3309         memset (ctx, 0, sizeof (VerifyContext));
3310         ctx->image = image;
3311         ctx->report_error = error_list != NULL;
3312         ctx->report_warning = FALSE; //export this setting in the API
3313         ctx->valid = 1;
3314         ctx->size = image->raw_data_len;
3315         ctx->data = image->raw_data;
3316 }
3317
3318 static gboolean
3319 cleanup_context (VerifyContext *ctx, GSList **error_list)
3320 {
3321         g_free (ctx->sections);
3322         if (error_list)
3323                 *error_list = ctx->errors;
3324         else
3325                 mono_free_verify_list (ctx->errors);
3326         return ctx->valid;      
3327 }
3328
3329 gboolean
3330 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3331 {
3332         VerifyContext ctx;
3333
3334         if (!mono_verifier_is_enabled_for_image (image))
3335                 return TRUE;
3336
3337         init_verify_context (&ctx, image, error_list);
3338         ctx.stage = STAGE_PE;
3339
3340         verify_msdos_header (&ctx);
3341         CHECK_STATE();
3342         verify_pe_header (&ctx);
3343         CHECK_STATE();
3344         verify_pe_optional_header (&ctx);
3345         CHECK_STATE();
3346         load_section_table (&ctx);
3347         CHECK_STATE();
3348         load_data_directories (&ctx);
3349         CHECK_STATE();
3350         verify_import_table (&ctx);
3351         CHECK_STATE();
3352         /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3353         verify_resources_table (&ctx);
3354
3355 cleanup:
3356         return cleanup_context (&ctx, error_list);
3357 }
3358
3359 gboolean
3360 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3361 {
3362         VerifyContext ctx;
3363
3364         if (!mono_verifier_is_enabled_for_image (image))
3365                 return TRUE;
3366
3367         init_verify_context (&ctx, image, error_list);
3368         ctx.stage = STAGE_CLI;
3369
3370         verify_cli_header (&ctx);
3371         CHECK_STATE();
3372         verify_metadata_header (&ctx);
3373         CHECK_STATE();
3374         verify_tables_schema (&ctx);
3375
3376 cleanup:
3377         return cleanup_context (&ctx, error_list);
3378 }
3379
3380
3381 /*
3382  * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3383  * Other verification checks are meant to be done lazily by the runtime. Those include:
3384  *      blob items (signatures, method headers, custom attributes, etc)
3385  *  type semantics related
3386  *  vtable related
3387  *  stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3388  * 
3389  * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3390  * operation still need more checking.
3391  */
3392 gboolean
3393 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3394 {
3395         VerifyContext ctx;
3396
3397         if (!mono_verifier_is_enabled_for_image (image))
3398                 return TRUE;
3399
3400         init_verify_context (&ctx, image, error_list);
3401         ctx.stage = STAGE_TABLES;
3402
3403         verify_tables_data (&ctx);
3404
3405         return cleanup_context (&ctx, error_list);
3406 }
3407
3408
3409 /*
3410  * Verifies all other constraints.
3411  */
3412 gboolean
3413 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3414 {
3415         VerifyContext ctx;
3416
3417         if (!mono_verifier_is_enabled_for_image (image))
3418                 return TRUE;
3419
3420         init_verify_context (&ctx, image, error_list);
3421         ctx.stage = STAGE_TABLES;
3422
3423         verify_typedef_table_full (&ctx);
3424         CHECK_STATE ();
3425         verify_field_table_full (&ctx);
3426         CHECK_STATE ();
3427         verify_method_table_full (&ctx);
3428         CHECK_STATE ();
3429         verify_memberref_table_full (&ctx);
3430         CHECK_STATE ();
3431         verify_cattr_table_full (&ctx);
3432         CHECK_STATE ();
3433         verify_field_marshal_table_full (&ctx);
3434         CHECK_STATE ();
3435         verify_decl_security_table_full (&ctx);
3436         CHECK_STATE ();
3437         verify_standalonesig_table_full (&ctx);
3438         CHECK_STATE ();
3439         verify_event_table_full (&ctx);
3440         CHECK_STATE ();
3441         verify_typespec_table_full (&ctx);
3442         CHECK_STATE ();
3443         verify_method_spec_table_full (&ctx);
3444
3445 cleanup:
3446         return cleanup_context (&ctx, error_list);
3447 }
3448
3449 gboolean
3450 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3451 {
3452         VerifyContext ctx;
3453
3454         if (!mono_verifier_is_enabled_for_image (image))
3455                 return TRUE;
3456
3457         init_verify_context (&ctx, image, error_list);
3458         ctx.stage = STAGE_TABLES;
3459
3460         is_valid_field_signature (&ctx, offset);
3461         return cleanup_context (&ctx, error_list);
3462 }
3463
3464 gboolean
3465 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3466 {
3467         VerifyContext ctx;
3468
3469         if (!mono_verifier_is_enabled_for_image (image))
3470                 return TRUE;
3471
3472         init_verify_context (&ctx, image, error_list);
3473         ctx.stage = STAGE_TABLES;
3474
3475         is_valid_method_header (&ctx, offset);
3476         return cleanup_context (&ctx, error_list);
3477 }
3478
3479 gboolean
3480 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3481 {
3482         VerifyContext ctx;
3483
3484         if (!mono_verifier_is_enabled_for_image (image))
3485                 return TRUE;
3486
3487         init_verify_context (&ctx, image, error_list);
3488         ctx.stage = STAGE_TABLES;
3489
3490         is_valid_method_signature (&ctx, offset);
3491         return cleanup_context (&ctx, error_list);
3492 }
3493
3494 gboolean
3495 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3496 {
3497         VerifyContext ctx;
3498
3499         if (!mono_verifier_is_enabled_for_image (image))
3500                 return TRUE;
3501
3502         init_verify_context (&ctx, image, error_list);
3503         ctx.stage = STAGE_TABLES;
3504
3505         is_valid_method_or_field_signature (&ctx, offset);
3506         return cleanup_context (&ctx, error_list);
3507 }
3508
3509 gboolean
3510 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3511 {
3512         VerifyContext ctx;
3513
3514         if (!mono_verifier_is_enabled_for_image (image))
3515                 return TRUE;
3516
3517         init_verify_context (&ctx, image, error_list);
3518         ctx.stage = STAGE_TABLES;
3519
3520         is_valid_standalonesig_blob (&ctx, offset);
3521         return cleanup_context (&ctx, error_list);
3522 }
3523
3524 gboolean
3525 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3526 {
3527         VerifyContext ctx;
3528
3529         if (!mono_verifier_is_enabled_for_image (image))
3530                 return TRUE;
3531
3532         init_verify_context (&ctx, image, error_list);
3533         ctx.stage = STAGE_TABLES;
3534
3535         is_valid_typespec_blob (&ctx, offset);
3536         return cleanup_context (&ctx, error_list);
3537 }
3538
3539 gboolean
3540 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3541 {
3542         VerifyContext ctx;
3543
3544         if (!mono_verifier_is_enabled_for_image (image))
3545                 return TRUE;
3546
3547         init_verify_context (&ctx, image, error_list);
3548         ctx.stage = STAGE_TABLES;
3549
3550         is_valid_methodspec_blog (&ctx, offset);
3551         return cleanup_context (&ctx, error_list);
3552 }
3553
3554 #else
3555 gboolean
3556 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3557 {
3558         return TRUE;
3559 }
3560
3561 gboolean
3562 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3563 {
3564         return TRUE;
3565 }
3566
3567 gboolean
3568 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3569 {
3570         return TRUE;
3571 }
3572
3573 gboolean
3574 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3575 {
3576         return TRUE;
3577 }
3578
3579 gboolean
3580 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3581 {
3582         return TRUE;
3583 }
3584
3585 gboolean
3586 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3587 {
3588         return TRUE;
3589 }
3590
3591 gboolean
3592 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3593 {
3594         return TRUE;
3595 }
3596
3597 gboolean
3598 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3599 {
3600         return TRUE;
3601 }
3602
3603 gboolean
3604 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3605 {
3606         return TRUE;
3607 }
3608
3609 gboolean
3610 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3611 {
3612         return TRUE;
3613 }
3614
3615 gboolean
3616 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3617 {
3618         return TRUE;
3619 }
3620
3621 #endif /* DISABLE_VERIFIER */