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