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