Requires gmcs
[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) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
2266                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2267
2268                 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && 
2269                                 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2270                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2271
2272                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2273                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2274
2275                 //TODO check signature contents
2276
2277                 if (rva) {
2278                         if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2279                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2280                         if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2281                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2282                 } else {
2283                         if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2284                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2285                 }
2286
2287                 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2288                         if (rva)
2289                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2290                         if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2291                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2292                 }
2293                 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2294                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2295
2296                 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2297                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2298
2299                 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2300                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2301
2302                 if (data [MONO_METHOD_PARAMLIST] == 0)
2303                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2304
2305                 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2306                         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));
2307
2308                 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2309                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2310
2311                 paramlist = data [MONO_METHOD_PARAMLIST];
2312
2313         }
2314 }
2315
2316 static void
2317 verify_method_table_full (VerifyContext *ctx)
2318 {
2319         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2320         guint32 data [MONO_METHOD_SIZE], rva;
2321         int i;
2322
2323         for (i = 0; i < table->rows; ++i) {
2324                 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2325                 rva = data [MONO_METHOD_RVA];
2326
2327                 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2328                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2329
2330                 if (rva && !is_valid_method_header (ctx, rva))
2331                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2332         }
2333 }
2334
2335 static guint32
2336 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2337 {
2338         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2339         guint32 row = *current_method;
2340         guint32 paramlist, tmp;
2341
2342
2343         paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2344         while (row < table->rows) {
2345                 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2346                 if (tmp > paramlist) {
2347                         *current_method = row;
2348                         return tmp - paramlist;
2349                 }
2350                 ++row;
2351         }
2352
2353         /*no more methods, all params apply to the last one*/
2354         *current_method = table->rows;
2355         return (guint32)-1;
2356 }
2357
2358
2359 #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))
2360 static void
2361 verify_param_table (VerifyContext *ctx)
2362 {
2363         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2364         guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2365         gboolean first_param = TRUE;
2366         int i;
2367
2368         if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2369                 if (table->rows > 0)
2370                         ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2371                 return;
2372         }
2373         
2374         remaining_params = get_next_param_count (ctx, &current_method);
2375
2376         for (i = 0; i < table->rows; ++i) {
2377                 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2378                 flags = data [MONO_PARAM_FLAGS];
2379
2380                 if (flags & INVALID_PARAM_FLAGS_BITS)
2381                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2382
2383                 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2384                         if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2385                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2386                 } else {
2387                         if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2388                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2389                 }
2390
2391                 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)
2392                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2393
2394                 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2395                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2396
2397                 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2398                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2399
2400                 first_param = FALSE;
2401                 sequence = data [MONO_PARAM_SEQUENCE];
2402                 if (--remaining_params == 0) {
2403                         remaining_params = get_next_param_count (ctx, &current_method);
2404                         first_param = TRUE;
2405                 }
2406         }
2407 }
2408
2409 static void
2410 verify_interfaceimpl_table (VerifyContext *ctx)
2411 {
2412         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2413         guint32 data [MONO_INTERFACEIMPL_SIZE];
2414         int i;
2415
2416         for (i = 0; i < table->rows; ++i) {
2417                 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2418                 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2419                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2420
2421                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2422                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2423
2424                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2425                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2426         }
2427 }
2428
2429 static void
2430 verify_memberref_table (VerifyContext *ctx)
2431 {
2432         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2433         guint32 data [MONO_MEMBERREF_SIZE];
2434         int i;
2435
2436         for (i = 0; i < table->rows; ++i) {
2437                 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2438
2439                 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2440                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2441
2442                 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2443                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2444
2445                 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2446                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2447
2448                 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2449                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2450         }
2451 }
2452
2453
2454 static void
2455 verify_memberref_table_full (VerifyContext *ctx)
2456 {
2457         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2458         guint32 data [MONO_MEMBERREF_SIZE];
2459         int i;
2460
2461         for (i = 0; i < table->rows; ++i) {
2462                 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2463
2464                 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2465                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field  0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2466         }
2467 }
2468
2469 static void
2470 verify_constant_table (VerifyContext *ctx)
2471 {
2472         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2473         guint32 data [MONO_CONSTANT_SIZE], type;
2474         int i;
2475
2476         for (i = 0; i < table->rows; ++i) {
2477                 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2478                 type = data [MONO_CONSTANT_TYPE];
2479
2480                 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2481                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2482
2483                 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2484                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2485
2486                 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2487                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2488
2489                 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2490                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2491         }
2492 }
2493
2494 static void
2495 verify_cattr_table (VerifyContext *ctx)
2496 {
2497         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2498         guint32 data [MONO_CUSTOM_ATTR_SIZE];
2499         int i;
2500
2501         for (i = 0; i < table->rows; ++i) {
2502                 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2503
2504                 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2505                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2506
2507                 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2508                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2509
2510                 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2511                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2512         }
2513 }
2514
2515 static void
2516 verify_cattr_table_full (VerifyContext *ctx)
2517 {
2518         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2519         guint32 data [MONO_CUSTOM_ATTR_SIZE];
2520         int i;
2521
2522         for (i = 0; i < table->rows; ++i) {
2523                 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2524
2525                 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2526                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2527         }
2528 }
2529
2530 static void
2531 verify_field_marshal_table (VerifyContext *ctx)
2532 {
2533         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2534         guint32 data [MONO_FIELD_MARSHAL_SIZE];
2535         int i;
2536
2537         for (i = 0; i < table->rows; ++i) {
2538                 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2539
2540                 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2541                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2542
2543                 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2544                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2545
2546                 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2547                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2548
2549                 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2550                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2551         }
2552 }
2553
2554 static void
2555 verify_field_marshal_table_full (VerifyContext *ctx)
2556 {
2557         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2558         guint32 data [MONO_FIELD_MARSHAL_SIZE];
2559         int i;
2560
2561         for (i = 0; i < table->rows; ++i) {
2562                 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2563
2564                 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2565                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2566         }
2567 }
2568
2569 static void
2570 verify_decl_security_table (VerifyContext *ctx)
2571 {
2572         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2573         guint32 data [MONO_DECL_SECURITY_SIZE];
2574         int i;
2575
2576         for (i = 0; i < table->rows; ++i) {
2577                 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2578
2579                 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2580                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2581
2582                 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2583                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2584
2585                 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2586                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2587         }
2588 }
2589
2590 static void
2591 verify_decl_security_table_full (VerifyContext *ctx)
2592 {
2593         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2594         guint32 data [MONO_DECL_SECURITY_SIZE];
2595         int i;
2596
2597         for (i = 0; i < table->rows; ++i) {
2598                 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2599
2600                 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2601                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2602         }
2603 }
2604
2605 static void
2606 verify_class_layout_table (VerifyContext *ctx)
2607 {
2608         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2609         guint32 data [MONO_CLASS_LAYOUT_SIZE];
2610         int i;
2611
2612         for (i = 0; i < table->rows; ++i) {
2613                 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2614
2615                 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2616                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2617
2618                 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2619                 case 0:
2620                 case 1:
2621                 case 2:
2622                 case 4:
2623                 case 8:
2624                 case 16:
2625                 case 32:
2626                 case 64:
2627                 case 128:
2628                         break;
2629                 default:
2630                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2631                 }
2632         }
2633 }
2634
2635 static void
2636 verify_field_layout_table (VerifyContext *ctx)
2637 {
2638         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2639         guint32 data [MONO_FIELD_LAYOUT_SIZE];
2640         int i;
2641
2642         for (i = 0; i < table->rows; ++i) {
2643                 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2644
2645                 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2646                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2647         }
2648 }
2649
2650 static void
2651 verify_standalonesig_table (VerifyContext *ctx)
2652 {
2653         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2654         guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2655         int i;
2656
2657         for (i = 0; i < table->rows; ++i) {
2658                 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2659
2660                 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
2661                         ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2662         }
2663 }
2664
2665 static void
2666 verify_standalonesig_table_full (VerifyContext *ctx)
2667 {
2668         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2669         guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2670         int i;
2671
2672         for (i = 0; i < table->rows; ++i) {
2673                 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2674
2675                 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2676                         ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2677         }
2678 }
2679
2680 static void
2681 verify_eventmap_table (VerifyContext *ctx)
2682 {
2683         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2684         guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2685         int i;
2686
2687         for (i = 0; i < table->rows; ++i) {
2688                 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2689
2690                 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2691                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2692
2693                 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2694                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2695
2696                 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2697         }
2698 }
2699
2700 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2701 static void
2702 verify_event_table (VerifyContext *ctx)
2703 {
2704         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2705         guint32 data [MONO_EVENT_SIZE];
2706         int i;
2707
2708         for (i = 0; i < table->rows; ++i) {
2709                 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2710
2711                 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2712                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2713
2714                 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2715                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2716
2717                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2718                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2719         }
2720 }
2721
2722 static void
2723 verify_event_table_full (VerifyContext *ctx)
2724 {
2725         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2726         MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2727         guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2728         gboolean found_add, found_remove;
2729         int i, idx;
2730
2731         for (i = 0; i < table->rows; ++i) {
2732                 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2733
2734                 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2735                 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2736                 if (idx == -1)
2737                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2738
2739                 //first we move to the first row for this event
2740                 while (idx > 0) {
2741                         if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2742                                 break;
2743                         --idx;
2744                 }
2745                 //now move forward looking for AddOn and RemoveOn rows
2746                 found_add = found_remove = FALSE;
2747                 while (idx < sema_table->rows) {
2748                         mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2749                         if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2750                                 break;
2751                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2752                                 found_add = TRUE;
2753                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2754                                 found_remove = TRUE;
2755                         if (found_add && found_remove)
2756                                 break;
2757                         ++idx;
2758                 }
2759
2760                 if (!found_add)
2761                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2762                 if (!found_remove)
2763                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2764         }
2765 }
2766
2767 static void
2768 verify_propertymap_table (VerifyContext *ctx)
2769 {
2770         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2771         guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2772         int i;
2773
2774         for (i = 0; i < table->rows; ++i) {
2775                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2776
2777                 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2778                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2779
2780                 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2781                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2782
2783                 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2784         }
2785 }
2786
2787 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2788 static void
2789 verify_property_table (VerifyContext *ctx)
2790 {
2791         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2792         guint32 data [MONO_PROPERTY_SIZE];
2793         int i;
2794
2795         for (i = 0; i < table->rows; ++i) {
2796                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2797
2798                 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2799                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2800
2801                 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2802                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2803
2804                 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2805                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2806
2807                 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2808                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2809                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2810
2811         }
2812 }
2813
2814 static void
2815 verify_methodimpl_table (VerifyContext *ctx)
2816 {
2817         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2818         guint32 data [MONO_METHODIMPL_SIZE];
2819         int i;
2820
2821         for (i = 0; i < table->rows; ++i) {
2822                 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2823
2824                 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2825                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2826                         
2827                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2828                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2829                 
2830                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2831                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2832
2833                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2834                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2835                 
2836                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2837                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2838         }
2839 }
2840
2841 static void
2842 verify_moduleref_table (VerifyContext *ctx)
2843 {
2844         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2845         guint32 data [MONO_MODULEREF_SIZE];
2846         int i;
2847
2848         for (i = 0; i < table->rows; ++i) {
2849                 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2850
2851                 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2852                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2853         }
2854 }
2855
2856 static void
2857 verify_typespec_table (VerifyContext *ctx)
2858 {
2859         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2860         guint32 data [MONO_TYPESPEC_SIZE];
2861         int i;
2862
2863         for (i = 0; i < table->rows; ++i) {
2864                 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2865
2866                 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
2867                         ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2868         }
2869 }
2870
2871 static void
2872 verify_typespec_table_full (VerifyContext *ctx)
2873 {
2874         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2875         guint32 data [MONO_TYPESPEC_SIZE];
2876         int i;
2877
2878         for (i = 0; i < table->rows; ++i) {
2879                 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2880
2881                 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2882                         ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2883         }
2884 }
2885
2886 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
2887 static void
2888 verify_implmap_table (VerifyContext *ctx)
2889 {
2890         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2891         guint32 data [MONO_IMPLMAP_SIZE], cconv;
2892         int i;
2893
2894         for (i = 0; i < table->rows; ++i) {
2895                 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2896
2897                 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2898                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2899
2900                 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2901                 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2902                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2903
2904                 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2905                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2906
2907                 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2908                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2909
2910                 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2911                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2912
2913                 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2914                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2915
2916                 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
2917                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2918         }
2919 }
2920
2921 static void
2922 verify_fieldrva_table (VerifyContext *ctx)
2923 {
2924         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2925         guint32 data [MONO_FIELD_RVA_SIZE];
2926         int i;
2927
2928         for (i = 0; i < table->rows; ++i) {
2929                 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2930
2931                 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2932                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2933
2934                 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2935                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2936         }
2937 }
2938
2939 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
2940 static void
2941 verify_assembly_table (VerifyContext *ctx)
2942 {
2943         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2944         guint32 data [MONO_ASSEMBLY_SIZE], hash;
2945         int i;
2946
2947         if (table->rows > 1)
2948                 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2949
2950         for (i = 0; i < table->rows; ++i) {
2951                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2952
2953                 hash = data [MONO_ASSEMBLY_HASH_ALG];
2954                 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2955                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2956
2957                 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2958                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2959
2960                 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
2961                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2962
2963                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2964                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2965
2966                 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2967                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2968         }
2969 }
2970
2971 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2972 static void
2973 verify_assemblyref_table (VerifyContext *ctx)
2974 {
2975         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2976         guint32 data [MONO_ASSEMBLYREF_SIZE];
2977         int i;
2978
2979         for (i = 0; i < table->rows; ++i) {
2980                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2981
2982                 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2983                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2984
2985                 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
2986                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2987
2988                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2989                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
2990
2991                 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
2992                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
2993
2994                 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
2995                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
2996         }
2997 }
2998
2999 #define INVALID_FILE_FLAGS_BITS ~(1)
3000 static void
3001 verify_file_table (VerifyContext *ctx)
3002 {
3003         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3004         guint32 data [MONO_FILE_SIZE];
3005         int i;
3006
3007         for (i = 0; i < table->rows; ++i) {
3008                 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3009                 
3010                 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3011                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3012
3013                 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3014                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3015
3016                 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3017                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3018         }
3019 }
3020
3021 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3022 static void
3023 verify_exportedtype_table (VerifyContext *ctx)
3024 {
3025         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3026         guint32 data [MONO_EXP_TYPE_SIZE];
3027         int i;
3028
3029         for (i = 0; i < table->rows; ++i) {
3030                 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3031                 
3032                 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3033                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3034
3035                 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3036                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3037
3038                 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3039                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3040
3041                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3042                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3043
3044                 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3045                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3046
3047                 /*nested type can't have a namespace*/
3048                 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3049                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3050         }
3051 }
3052
3053 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3054 static void
3055 verify_manifest_resource_table (VerifyContext *ctx)
3056 {
3057         MonoCLIImageInfo *iinfo = ctx->image->image_info;
3058         MonoCLIHeader *ch = &iinfo->cli_cli_header;
3059         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3060         guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3061         int i;
3062
3063         resources_size = ch->ch_resources.size;
3064
3065         for (i = 0; i < table->rows; ++i) {
3066                 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3067
3068                 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3069                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3070
3071                 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3072                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3073
3074                 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3075                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3076
3077                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3078                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3079
3080                 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3081                 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3082
3083                 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3084                         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])));
3085
3086                 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3087                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3088
3089                 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3090                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3091         }
3092 }
3093
3094 static void
3095 verify_nested_class_table (VerifyContext *ctx)
3096 {
3097         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3098         guint32 data [MONO_NESTED_CLASS_SIZE];
3099         int i;
3100
3101         for (i = 0; i < table->rows; ++i) {
3102                 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3103
3104                 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3105                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3106                 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3107                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3108                 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3109                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass  and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3110         }
3111 }
3112
3113 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3114 static void
3115 verify_generic_param_table (VerifyContext *ctx)
3116 {
3117         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3118         guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3119         int i, param_number = 0;
3120
3121         for (i = 0; i < table->rows; ++i) {
3122                 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3123
3124                 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3125                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3126
3127                 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3128                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3129
3130                 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3131                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3132
3133                 token = data [MONO_GENERICPARAM_OWNER];
3134
3135                 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3136                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3137
3138                 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3139                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3140
3141                 if (token != last_token) {
3142                         param_number = 0;
3143                         last_token = token;
3144                 }
3145
3146                 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3147                         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));
3148
3149                 ++param_number;
3150         }
3151 }
3152
3153 static void
3154 verify_method_spec_table (VerifyContext *ctx)
3155 {
3156         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3157         guint32 data [MONO_METHODSPEC_SIZE];
3158         int i;
3159
3160         for (i = 0; i < table->rows; ++i) {
3161                 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3162
3163                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3164                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3165
3166                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3167                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3168
3169                 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3170                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3171         }
3172 }
3173
3174 static void
3175 verify_method_spec_table_full (VerifyContext *ctx)
3176 {
3177         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3178         guint32 data [MONO_METHODSPEC_SIZE];
3179         int i;
3180
3181         for (i = 0; i < table->rows; ++i) {
3182                 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3183
3184                 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3185                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3186         }
3187 }
3188
3189 static void
3190 verify_generic_param_constraint_table (VerifyContext *ctx)
3191 {
3192         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3193         guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3194         int i;
3195
3196         for (i = 0; i < table->rows; ++i) {
3197                 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3198
3199                 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3200                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3201
3202                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3203                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3204
3205                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3206                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3207         }
3208 }
3209
3210 static void
3211 verify_tables_data (VerifyContext *ctx)
3212 {
3213         OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3214         guint32 size = 0, tables_offset;
3215         int i;
3216
3217         for (i = 0; i < 0x2D; ++i) {
3218                 MonoTableInfo *table = &ctx->image->tables [i];
3219                 guint32 tmp_size;
3220                 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3221                 if (tmp_size < size) {
3222                         size = 0;
3223                         break;
3224                 }
3225                 size = tmp_size;                        
3226         }
3227
3228         if (size == 0)
3229                 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3230
3231         tables_offset = ctx->image->tables_base - ctx->data;
3232         if (!bounds_check_offset (&tables_area, tables_offset, size))
3233                 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)));
3234
3235         verify_module_table (ctx);
3236         CHECK_ERROR ();
3237         verify_typeref_table (ctx);
3238         CHECK_ERROR ();
3239         verify_typedef_table (ctx);
3240         CHECK_ERROR ();
3241         verify_field_table (ctx);
3242         CHECK_ERROR ();
3243         verify_method_table (ctx);
3244         CHECK_ERROR ();
3245         verify_param_table (ctx);
3246         CHECK_ERROR ();
3247         verify_interfaceimpl_table (ctx);
3248         CHECK_ERROR ();
3249         verify_memberref_table (ctx);
3250         CHECK_ERROR ();
3251         verify_constant_table (ctx);
3252         CHECK_ERROR ();
3253         verify_cattr_table (ctx);
3254         CHECK_ERROR ();
3255         verify_field_marshal_table (ctx);
3256         CHECK_ERROR ();
3257         verify_decl_security_table (ctx);
3258         CHECK_ERROR ();
3259         verify_class_layout_table (ctx);
3260         CHECK_ERROR ();
3261         verify_field_layout_table (ctx);
3262         CHECK_ERROR ();
3263         verify_standalonesig_table (ctx);
3264         CHECK_ERROR ();
3265         verify_eventmap_table (ctx);
3266         CHECK_ERROR ();
3267         verify_event_table (ctx);
3268         CHECK_ERROR ();
3269         verify_propertymap_table (ctx);
3270         CHECK_ERROR ();
3271         verify_property_table (ctx);
3272         CHECK_ERROR ();
3273         verify_methodimpl_table (ctx);
3274         CHECK_ERROR ();
3275         verify_moduleref_table (ctx);
3276         CHECK_ERROR ();
3277         verify_typespec_table (ctx);
3278         CHECK_ERROR ();
3279         verify_implmap_table (ctx);
3280         CHECK_ERROR ();
3281         verify_fieldrva_table (ctx);
3282         CHECK_ERROR ();
3283         verify_assembly_table (ctx);
3284         CHECK_ERROR ();
3285         verify_assemblyref_table (ctx);
3286         CHECK_ERROR ();
3287         verify_file_table (ctx);
3288         CHECK_ERROR ();
3289         verify_exportedtype_table (ctx);
3290         CHECK_ERROR ();
3291         verify_manifest_resource_table (ctx);
3292         CHECK_ERROR ();
3293         verify_nested_class_table (ctx);
3294         CHECK_ERROR ();
3295         verify_generic_param_table (ctx);
3296         CHECK_ERROR ();
3297         verify_method_spec_table (ctx);
3298         CHECK_ERROR ();
3299         verify_generic_param_constraint_table (ctx);
3300 }
3301
3302 static void
3303 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
3304 {
3305         memset (ctx, 0, sizeof (VerifyContext));
3306         ctx->image = image;
3307         ctx->report_error = error_list != NULL;
3308         ctx->report_warning = FALSE; //export this setting in the API
3309         ctx->valid = 1;
3310         ctx->size = image->raw_data_len;
3311         ctx->data = image->raw_data;
3312 }
3313
3314 static gboolean
3315 cleanup_context (VerifyContext *ctx, GSList **error_list)
3316 {
3317         g_free (ctx->sections);
3318         if (error_list)
3319                 *error_list = ctx->errors;
3320         else
3321                 mono_free_verify_list (ctx->errors);
3322         return ctx->valid;      
3323 }
3324
3325 gboolean
3326 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3327 {
3328         VerifyContext ctx;
3329
3330         if (!mono_verifier_is_enabled_for_image (image))
3331                 return TRUE;
3332
3333         init_verify_context (&ctx, image, error_list);
3334         ctx.stage = STAGE_PE;
3335
3336         verify_msdos_header (&ctx);
3337         CHECK_STATE();
3338         verify_pe_header (&ctx);
3339         CHECK_STATE();
3340         verify_pe_optional_header (&ctx);
3341         CHECK_STATE();
3342         load_section_table (&ctx);
3343         CHECK_STATE();
3344         load_data_directories (&ctx);
3345         CHECK_STATE();
3346         verify_import_table (&ctx);
3347         CHECK_STATE();
3348         /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3349         verify_resources_table (&ctx);
3350
3351 cleanup:
3352         return cleanup_context (&ctx, error_list);
3353 }
3354
3355 gboolean
3356 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3357 {
3358         VerifyContext ctx;
3359
3360         if (!mono_verifier_is_enabled_for_image (image))
3361                 return TRUE;
3362
3363         init_verify_context (&ctx, image, error_list);
3364         ctx.stage = STAGE_CLI;
3365
3366         verify_cli_header (&ctx);
3367         CHECK_STATE();
3368         verify_metadata_header (&ctx);
3369         CHECK_STATE();
3370         verify_tables_schema (&ctx);
3371
3372 cleanup:
3373         return cleanup_context (&ctx, error_list);
3374 }
3375
3376
3377 /*
3378  * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3379  * Other verification checks are meant to be done lazily by the runtime. Those include:
3380  *      blob items (signatures, method headers, custom attributes, etc)
3381  *  type semantics related
3382  *  vtable related
3383  *  stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3384  * 
3385  * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3386  * operation still need more checking.
3387  */
3388 gboolean
3389 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3390 {
3391         VerifyContext ctx;
3392
3393         if (!mono_verifier_is_enabled_for_image (image))
3394                 return TRUE;
3395
3396         init_verify_context (&ctx, image, error_list);
3397         ctx.stage = STAGE_TABLES;
3398
3399         verify_tables_data (&ctx);
3400
3401         return cleanup_context (&ctx, error_list);
3402 }
3403
3404
3405 /*
3406  * Verifies all other constraints.
3407  */
3408 gboolean
3409 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3410 {
3411         VerifyContext ctx;
3412
3413         if (!mono_verifier_is_enabled_for_image (image))
3414                 return TRUE;
3415
3416         init_verify_context (&ctx, image, error_list);
3417         ctx.stage = STAGE_TABLES;
3418
3419         verify_typedef_table_full (&ctx);
3420         CHECK_STATE ();
3421         verify_field_table_full (&ctx);
3422         CHECK_STATE ();
3423         verify_method_table_full (&ctx);
3424         CHECK_STATE ();
3425         verify_memberref_table_full (&ctx);
3426         CHECK_STATE ();
3427         verify_cattr_table_full (&ctx);
3428         CHECK_STATE ();
3429         verify_field_marshal_table_full (&ctx);
3430         CHECK_STATE ();
3431         verify_decl_security_table_full (&ctx);
3432         CHECK_STATE ();
3433         verify_standalonesig_table_full (&ctx);
3434         CHECK_STATE ();
3435         verify_event_table_full (&ctx);
3436         CHECK_STATE ();
3437         verify_typespec_table_full (&ctx);
3438         CHECK_STATE ();
3439         verify_method_spec_table_full (&ctx);
3440
3441 cleanup:
3442         return cleanup_context (&ctx, error_list);
3443 }
3444
3445 gboolean
3446 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3447 {
3448         VerifyContext ctx;
3449
3450         if (!mono_verifier_is_enabled_for_image (image))
3451                 return TRUE;
3452
3453         init_verify_context (&ctx, image, error_list);
3454         ctx.stage = STAGE_TABLES;
3455
3456         is_valid_field_signature (&ctx, offset);
3457         return cleanup_context (&ctx, error_list);
3458 }
3459
3460 gboolean
3461 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3462 {
3463         VerifyContext ctx;
3464
3465         if (!mono_verifier_is_enabled_for_image (image))
3466                 return TRUE;
3467
3468         init_verify_context (&ctx, image, error_list);
3469         ctx.stage = STAGE_TABLES;
3470
3471         is_valid_method_header (&ctx, offset);
3472         return cleanup_context (&ctx, error_list);
3473 }
3474
3475 gboolean
3476 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3477 {
3478         VerifyContext ctx;
3479
3480         if (!mono_verifier_is_enabled_for_image (image))
3481                 return TRUE;
3482
3483         init_verify_context (&ctx, image, error_list);
3484         ctx.stage = STAGE_TABLES;
3485
3486         is_valid_method_signature (&ctx, offset);
3487         return cleanup_context (&ctx, error_list);
3488 }
3489
3490 gboolean
3491 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3492 {
3493         VerifyContext ctx;
3494
3495         if (!mono_verifier_is_enabled_for_image (image))
3496                 return TRUE;
3497
3498         init_verify_context (&ctx, image, error_list);
3499         ctx.stage = STAGE_TABLES;
3500
3501         is_valid_method_or_field_signature (&ctx, offset);
3502         return cleanup_context (&ctx, error_list);
3503 }
3504
3505 gboolean
3506 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3507 {
3508         VerifyContext ctx;
3509
3510         if (!mono_verifier_is_enabled_for_image (image))
3511                 return TRUE;
3512
3513         init_verify_context (&ctx, image, error_list);
3514         ctx.stage = STAGE_TABLES;
3515
3516         is_valid_standalonesig_blob (&ctx, offset);
3517         return cleanup_context (&ctx, error_list);
3518 }
3519
3520 gboolean
3521 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3522 {
3523         VerifyContext ctx;
3524
3525         if (!mono_verifier_is_enabled_for_image (image))
3526                 return TRUE;
3527
3528         init_verify_context (&ctx, image, error_list);
3529         ctx.stage = STAGE_TABLES;
3530
3531         is_valid_typespec_blob (&ctx, offset);
3532         return cleanup_context (&ctx, error_list);
3533 }
3534
3535 gboolean
3536 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3537 {
3538         VerifyContext ctx;
3539
3540         if (!mono_verifier_is_enabled_for_image (image))
3541                 return TRUE;
3542
3543         init_verify_context (&ctx, image, error_list);
3544         ctx.stage = STAGE_TABLES;
3545
3546         is_valid_methodspec_blog (&ctx, offset);
3547         return cleanup_context (&ctx, error_list);
3548 }
3549
3550 #else
3551 gboolean
3552 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3553 {
3554         return TRUE;
3555 }
3556
3557 gboolean
3558 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3559 {
3560         return TRUE;
3561 }
3562
3563 gboolean
3564 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3565 {
3566         return TRUE;
3567 }
3568
3569 gboolean
3570 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3571 {
3572         return TRUE;
3573 }
3574
3575 gboolean
3576 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3577 {
3578         return TRUE;
3579 }
3580
3581 gboolean
3582 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3583 {
3584         return TRUE;
3585 }
3586
3587 gboolean
3588 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3589 {
3590         return TRUE;
3591 }
3592
3593 gboolean
3594 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3595 {
3596         return TRUE;
3597 }
3598
3599 gboolean
3600 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3601 {
3602         return TRUE;
3603 }
3604
3605 gboolean
3606 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3607 {
3608         return TRUE;
3609 }
3610
3611 gboolean
3612 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3613 {
3614         return TRUE;
3615 }
3616
3617 #endif /* DISABLE_VERIFIER */