2009-09-01 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / metadata-verify.c
1 /*
2  * metadata-verify.c: Metadata verfication support
3  *
4  * Author:
5  *      Mono Project (http://www.mono-project.com)
6  *
7  * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
8  */
9 #include <mono/metadata/object-internals.h>
10 #include <mono/metadata/verify.h>
11 #include <mono/metadata/verify-internals.h>
12 #include <mono/metadata/opcodes.h>
13 #include <mono/metadata/tabledefs.h>
14 #include <mono/metadata/reflection.h>
15 #include <mono/metadata/debug-helpers.h>
16 #include <mono/metadata/mono-endian.h>
17 #include <mono/metadata/metadata.h>
18 #include <mono/metadata/metadata-internals.h>
19 #include <mono/metadata/class-internals.h>
20 #include <mono/metadata/tokentype.h>
21 #include <mono/metadata/security-manager.h>
22 #include <mono/metadata/security-core-clr.h>
23 #include <mono/metadata/cil-coff.h>
24 #include <mono/metadata/attrdefs.h>
25 #include <mono/utils/strenc.h>
26 #include <string.h>
27 //#include <signal.h>
28 #include <ctype.h>
29
30 #ifndef DISABLE_VERIFIER
31 /*
32  TODO add fail fast mode
33  TODO add PE32+ support
34  TODO verify the entry point RVA and content.
35  TODO load_section_table and load_data_directories must take PE32+ into account
36  TODO add section relocation support
37  TODO verify the relocation table, since we really don't use, no need so far.
38  TODO do full PECOFF resources verification 
39  TODO verify in the CLI header entry point and resources
40  TODO implement null token typeref validation  
41  TODO verify table wide invariants for typedef (sorting and uniqueness)
42  TODO implement proper authenticode data directory validation
43  TODO verify properties that require multiple tables to be valid 
44  FIXME use subtraction based bounds checking to avoid overflows
45  FIXME get rid of metadata_streams and other fields from VerifyContext
46 */
47
48 #ifdef MONO_VERIFIER_DEBUG
49 #define VERIFIER_DEBUG(code) do { code; } while (0)
50 #else
51 #define VERIFIER_DEBUG(code)
52 #endif
53
54 #define INVALID_OFFSET ((guint32)-1)
55 #define INVALID_ADDRESS 0xffffffff
56
57 enum {
58         STAGE_PE,
59         STAGE_CLI,
60         STAGE_TABLES
61 };
62
63 enum {
64         IMPORT_TABLE_IDX = 1, 
65         RESOURCE_TABLE_IDX = 2,
66         CERTIFICATE_TABLE_IDX = 4,
67         RELOCATION_TABLE_IDX = 5,
68         IAT_IDX = 12,
69         CLI_HEADER_IDX = 14,
70 };
71
72 enum {
73         STRINGS_STREAM,
74         USER_STRINGS_STREAM,
75         BLOB_STREAM,
76         GUID_STREAM,
77         TILDE_STREAM
78 };
79
80
81 #define INVALID_TABLE (0xFF)
82 /*format: number of bits, number of tables, tables{n. tables} */
83 const static unsigned char coded_index_desc[] = {
84 #define TYPEDEF_OR_REF_DESC (0)
85         2, /*bits*/
86         3, /*tables*/
87         MONO_TABLE_TYPEDEF,
88         MONO_TABLE_TYPEREF,
89         MONO_TABLE_TYPESPEC,
90
91 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
92         2, /*bits*/
93         3, /*tables*/
94         MONO_TABLE_FIELD,
95         MONO_TABLE_PARAM,
96         MONO_TABLE_PROPERTY,
97
98 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
99         5, /*bits*/
100         20, /*tables*/
101         MONO_TABLE_METHOD,
102         MONO_TABLE_FIELD,
103         MONO_TABLE_TYPEREF,
104         MONO_TABLE_TYPEDEF,
105         MONO_TABLE_PARAM,
106         MONO_TABLE_INTERFACEIMPL,
107         MONO_TABLE_MEMBERREF,
108         MONO_TABLE_MODULE,
109         MONO_TABLE_DECLSECURITY,
110         MONO_TABLE_PROPERTY, 
111         MONO_TABLE_EVENT,
112         MONO_TABLE_STANDALONESIG,
113         MONO_TABLE_MODULEREF,
114         MONO_TABLE_TYPESPEC,
115         MONO_TABLE_ASSEMBLY,
116         MONO_TABLE_ASSEMBLYREF,
117         MONO_TABLE_FILE,
118         MONO_TABLE_EXPORTEDTYPE,
119         MONO_TABLE_MANIFESTRESOURCE,
120         MONO_TABLE_GENERICPARAM,
121
122 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
123         1, /*bits*/
124         2, /*tables*/
125         MONO_TABLE_FIELD,
126         MONO_TABLE_PARAM,
127
128 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
129         2, /*bits*/
130         3, /*tables*/
131         MONO_TABLE_TYPEDEF,
132         MONO_TABLE_METHOD,
133         MONO_TABLE_ASSEMBLY,
134
135 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
136         3, /*bits*/
137         5, /*tables*/
138         MONO_TABLE_TYPEDEF,
139         MONO_TABLE_TYPEREF,
140         MONO_TABLE_MODULE,
141         MONO_TABLE_METHOD,
142         MONO_TABLE_TYPESPEC,
143
144 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
145         1, /*bits*/
146         2, /*tables*/
147         MONO_TABLE_EVENT,
148         MONO_TABLE_PROPERTY,
149
150 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
151         1, /*bits*/
152         2, /*tables*/
153         MONO_TABLE_METHOD,
154         MONO_TABLE_MEMBERREF,
155
156 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
157         1, /*bits*/
158         2, /*tables*/
159         MONO_TABLE_FIELD,
160         MONO_TABLE_METHOD,
161
162 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
163         2, /*bits*/
164         3, /*tables*/
165         MONO_TABLE_FILE,
166         MONO_TABLE_ASSEMBLYREF,
167         MONO_TABLE_EXPORTEDTYPE,
168
169 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
170         3, /*bits*/
171         5, /*tables*/
172         INVALID_TABLE,
173         INVALID_TABLE,
174         MONO_TABLE_METHOD,
175         MONO_TABLE_MEMBERREF,
176         INVALID_TABLE,
177
178 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
179         2, /*bits*/
180         4, /*tables*/
181         MONO_TABLE_MODULE,
182         MONO_TABLE_MODULEREF,
183         MONO_TABLE_ASSEMBLYREF,
184         MONO_TABLE_TYPEREF,
185
186 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
187         1, /*bits*/
188         2, /*tables*/
189         MONO_TABLE_TYPEDEF,
190         MONO_TABLE_METHOD
191 };
192
193 typedef struct {
194         guint32 rva;
195         guint32 size;
196         guint32 translated_offset;
197 } DataDirectory;
198
199 typedef struct {
200         guint32 offset;
201         guint32 size;
202 } OffsetAndSize;
203
204 typedef struct {
205         guint32 baseRVA;
206         guint32 baseOffset;
207         guint32 size;
208         guint32 rellocationsRVA;
209         guint16 numberOfRelocations;
210 } SectionHeader;
211
212 typedef struct {
213         guint32 row_count;
214         guint32 row_size;
215         guint32 offset;
216 } TableInfo;
217
218 typedef struct {
219         const char *data;
220         guint32 size;
221         GSList *errors;
222         int valid;
223         MonoImage *image;
224         gboolean report_error;
225         gboolean report_warning;
226         int stage;
227
228         DataDirectory data_directories [16];
229         guint32 section_count;
230         SectionHeader *sections;
231
232         OffsetAndSize metadata_streams [5]; //offset from begin of the image
233 } VerifyContext;
234
235 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception)    \
236         do {    \
237                 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1);      \
238                 vinfo->info.status = __status;  \
239                 vinfo->info.message = ( __msg); \
240                 vinfo->exception_type = (__exception);  \
241                 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo);     \
242         } while (0)
243
244 #define ADD_WARNING(__ctx, __msg)       \
245         do {    \
246                 if ((__ctx)->report_warning) { \
247                         ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
248                         (__ctx)->valid = 0; \
249                         return; \
250                 } \
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 verifies 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 (!safe_read_cint (count, ptr, end))
1271                 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1272
1273         if (count == 0)
1274                 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1275
1276         for (i = 0; i < count; ++i) {
1277                 if (!parse_type (ctx, &ptr, end))
1278                         FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1279         }
1280         *_ptr = ptr;
1281         return TRUE;
1282 }
1283
1284 static gboolean
1285 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1286 {
1287         const char *ptr = *_ptr;
1288         unsigned type;
1289         unsigned token = 0;
1290
1291         if (!safe_read8 (type, ptr, end))
1292                 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1293
1294         if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1295                 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1296                 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1297                 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1298                 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1299
1300         switch (type) {
1301         case MONO_TYPE_PTR:
1302                 if (!parse_custom_mods (ctx, &ptr, end))
1303                         FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1304
1305                 if (!safe_read8 (type, ptr, end))
1306                         FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1307
1308                 if (type != MONO_TYPE_VOID) {
1309                         --ptr;
1310                         if (!parse_type (ctx, &ptr, end))
1311                                 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1312                 }
1313                 break;
1314
1315         case MONO_TYPE_VALUETYPE:
1316         case MONO_TYPE_CLASS:
1317                 if (!safe_read_cint (token, ptr, end))
1318                         FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1319         
1320                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1321                         FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1322                 break;
1323
1324         case MONO_TYPE_VAR:
1325         case MONO_TYPE_MVAR:
1326                 if (!safe_read_cint (token, ptr, end))
1327                         FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1328                 break;
1329
1330         case MONO_TYPE_ARRAY:
1331                 if (!parse_type (ctx, &ptr, end))
1332                         FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1333                 if (!parse_array_shape (ctx, &ptr, end))
1334                         FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1335                 break;
1336
1337         case MONO_TYPE_GENERICINST:
1338                 if (!parse_generic_inst (ctx, &ptr, end))
1339                         FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1340                 break;
1341
1342         case MONO_TYPE_FNPTR:
1343                 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1344                         FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1345                 break;
1346
1347         case MONO_TYPE_SZARRAY:
1348                 if (!parse_custom_mods (ctx, &ptr, end))
1349                         FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1350                 if (!parse_type (ctx, &ptr, end))
1351                         FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1352                 break;
1353         }
1354         *_ptr = ptr;
1355         return TRUE;
1356 }
1357
1358 static gboolean
1359 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1360 {
1361         const char *ptr;
1362         unsigned type = 0;
1363
1364         if (!parse_custom_mods (ctx, _ptr, end))
1365                 return FALSE;
1366
1367         ptr = *_ptr;
1368         if (!safe_read8 (type, ptr, end))
1369                 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1370
1371         if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1372                 *_ptr = ptr;
1373                 return TRUE;
1374         }
1375
1376         //it's a byref, update the cursor ptr
1377         if (type == MONO_TYPE_BYREF)
1378                 *_ptr = ptr;
1379
1380         return parse_type (ctx, _ptr, end);
1381 }
1382
1383 static gboolean
1384 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1385 {
1386         const char *ptr;
1387         unsigned type = 0;
1388
1389         if (!parse_custom_mods (ctx, _ptr, end))
1390                 return FALSE;
1391
1392         ptr = *_ptr;
1393         if (!safe_read8 (type, ptr, end))
1394                 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1395
1396         if (type == MONO_TYPE_TYPEDBYREF) {
1397                 *_ptr = ptr;
1398                 return TRUE;
1399         }
1400
1401         //it's a byref, update the cursor ptr
1402         if (type == MONO_TYPE_BYREF)
1403                 *_ptr = ptr;
1404
1405         return parse_type (ctx, _ptr, end);
1406 }
1407
1408 static gboolean
1409 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1410 {
1411         unsigned cconv = 0;
1412         unsigned param_count = 0, gparam_count = 0, type = 0, i;
1413         const char *ptr = *_ptr;
1414         gboolean saw_sentinel = FALSE;
1415
1416         if (!safe_read8 (cconv, ptr, end))
1417                 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1418
1419         if (cconv & 0x80)
1420                 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1421
1422         if (allow_unmanaged) {
1423                 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1424                         FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1425         } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1426                 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1427
1428         if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1429                 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1430
1431         if ((cconv & 0x10) && gparam_count == 0)
1432                 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1433
1434         if (allow_unmanaged && (cconv & 0x10))
1435                 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1436
1437         if (!safe_read_cint (param_count, ptr, end))
1438                 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1439
1440         if (!parse_return_type (ctx, &ptr, end))
1441                 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1442
1443         for (i = 0; i < param_count; ++i) {
1444                 if (allow_sentinel) {
1445                         if (!safe_read8 (type, ptr, end))
1446                                 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1447
1448                         if (type == MONO_TYPE_SENTINEL) {
1449                                 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1450                                         FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1451
1452                                 if (saw_sentinel)
1453                                         FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1454
1455                                 saw_sentinel = TRUE;
1456                         } else {
1457                                 --ptr;
1458                         }
1459                 }
1460
1461                 if (!parse_param (ctx, &ptr, end))
1462                         FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1463         }
1464
1465         *_ptr = ptr;
1466         return TRUE;
1467 }
1468
1469 static gboolean
1470 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1471 {
1472         unsigned sig = 0;
1473         unsigned param_count = 0, i;
1474         const char *ptr = *_ptr;
1475
1476         if (!safe_read8 (sig, ptr, end))
1477                 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1478
1479         if (sig != 0x08 && sig != 0x28)
1480                 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1481
1482         if (!safe_read_cint (param_count, ptr, end))
1483                 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1484
1485         if (!parse_custom_mods (ctx, &ptr, end))
1486                 return FALSE;
1487
1488         if (!parse_type (ctx, &ptr, end))
1489                 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1490
1491         for (i = 0; i < param_count; ++i) {
1492                 if (!parse_type (ctx, &ptr, end))
1493                         FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1494         }
1495
1496         *_ptr = ptr;
1497         return TRUE;
1498 }
1499
1500 static gboolean
1501 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1502 {
1503         const char *ptr = *_ptr;
1504         unsigned signature = 0;
1505
1506         if (!safe_read8 (signature, ptr, end))
1507                 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1508
1509         if (signature != 0x06)
1510                 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1511
1512         if (!parse_custom_mods (ctx, &ptr, end))
1513                 return FALSE;
1514
1515         if (safe_read8 (signature, ptr, end)) {
1516                 if (signature != MONO_TYPE_BYREF)
1517                         --ptr;
1518         }
1519         *_ptr = ptr;
1520
1521         return parse_type (ctx, _ptr, end);
1522 }
1523
1524 static gboolean
1525 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1526 {
1527         unsigned sig = 0;
1528         unsigned locals_count = 0, i;
1529         const char *ptr = *_ptr;        
1530
1531         if (!safe_read8 (sig, ptr, end))
1532                 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1533
1534         if (sig != 0x07)
1535                 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1536
1537         if (!safe_read_cint (locals_count, ptr, end))
1538                 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1539
1540         /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1541         if (locals_count == 0)
1542                 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1543         */
1544
1545         for (i = 0; i < locals_count; ++i) {
1546                 if (!safe_read8 (sig, ptr, end))
1547                         FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1548
1549                 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1550                         if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1551                                 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1552                         if (!safe_read8 (sig, ptr, end))
1553                                 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1554                 }
1555
1556                 if (sig == MONO_TYPE_BYREF) {
1557                         if (!safe_read8 (sig, ptr, end))
1558                                 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1559                         if (sig == MONO_TYPE_TYPEDBYREF)
1560                                 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1561                 }
1562
1563                 if (sig == MONO_TYPE_TYPEDBYREF)
1564                         continue;
1565
1566                 --ptr;
1567
1568                 if (!parse_type (ctx, &ptr, end))
1569                         FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1570         }
1571
1572         *_ptr = ptr;
1573         return TRUE;
1574 }
1575
1576 static gboolean
1577 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1578 {
1579         int size = 0;
1580         unsigned signature = 0;
1581         const char *ptr = NULL, *end;
1582
1583         if (!decode_signature_header (ctx, offset, &size, &ptr))
1584                 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1585         end = ptr + size;
1586
1587         if (!safe_read8 (signature, ptr, end))
1588                 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1589
1590         if (signature != 6)
1591                 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1592         --ptr;
1593
1594         return parse_field (ctx, &ptr, end);
1595 }
1596
1597 static gboolean
1598 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1599 {
1600         int size = 0;
1601         const char *ptr = NULL, *end;
1602
1603         if (!decode_signature_header (ctx, offset, &size, &ptr))
1604                 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1605         end = ptr + size;
1606
1607         return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1608 }
1609
1610 static gboolean
1611 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1612 {
1613         int size = 0;
1614         unsigned signature = 0;
1615         const char *ptr = NULL, *end;
1616
1617         if (!decode_signature_header (ctx, offset, &size, &ptr))
1618                 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1619         end = ptr + size;
1620
1621         if (!safe_read8 (signature, ptr, end))
1622                 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1623         --ptr;
1624
1625         if (signature == 0x06)
1626                 return parse_field (ctx, &ptr, end);
1627
1628         return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1629 }
1630
1631 static gboolean
1632 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1633 {
1634         int size = 0;
1635         unsigned prolog = 0;
1636         const char *ptr = NULL, *end;
1637
1638         if (!offset)
1639                 return TRUE;
1640
1641         if (!decode_signature_header (ctx, offset, &size, &ptr))
1642                 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1643         end = ptr + size;
1644
1645         if (!safe_read16 (prolog, ptr, end))
1646                 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1647
1648         if (prolog != 1)
1649                 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1650                 
1651         return TRUE;
1652 }
1653
1654 static gboolean
1655 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1656 {
1657         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1658         //TODO do proper verification
1659         return blob.size >= 1 && blob.size - 1 >= offset;
1660 }
1661
1662 static gboolean
1663 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1664 {
1665         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1666         //TODO do proper verification
1667         return blob.size >= 1 && blob.size - 1 >= offset;
1668 }
1669
1670 static gboolean
1671 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1672 {
1673         int size = 0;
1674         unsigned signature = 0;
1675         const char *ptr = NULL, *end;
1676
1677         if (!decode_signature_header (ctx, offset, &size, &ptr))
1678                 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1679         end = ptr + size;
1680
1681         if (!safe_read8 (signature, ptr, end))
1682                 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1683
1684         --ptr;
1685         if (signature == 0x07)
1686                 return parse_locals_signature (ctx, &ptr, end);
1687         return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1688 }
1689
1690 static gboolean
1691 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1692 {
1693         int size = 0;
1694         const char *ptr = NULL, *end;
1695
1696         if (!decode_signature_header (ctx, offset, &size, &ptr))
1697                 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
1698         end = ptr + size;
1699
1700         return parse_property_signature (ctx, &ptr, end);
1701 }
1702
1703 static gboolean
1704 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1705 {
1706         int size = 0;
1707         const char *ptr = NULL, *end;
1708         unsigned type = 0;
1709         
1710
1711         if (!decode_signature_header (ctx, offset, &size, &ptr))
1712                 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
1713         end = ptr + size;
1714
1715         if (!parse_custom_mods (ctx, &ptr, end))
1716                 return FALSE;
1717
1718         if (!safe_read8 (type, ptr, end))
1719                 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
1720
1721         if (type == MONO_TYPE_BYREF) {
1722                 if (!safe_read8 (type, ptr, end)) 
1723                         FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
1724                 if (type == MONO_TYPE_TYPEDBYREF)
1725                         FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
1726         }
1727         
1728         if (type == MONO_TYPE_TYPEDBYREF)
1729                 return TRUE;
1730
1731         --ptr;
1732         return parse_type (ctx, &ptr, end);
1733 }
1734
1735 static gboolean
1736 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1737 {
1738         int size = 0;
1739         const char *ptr = NULL, *end;
1740         unsigned type = 0;
1741         unsigned count = 0, i;
1742
1743         if (!decode_signature_header (ctx, offset, &size, &ptr))
1744                 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
1745         end = ptr + size;
1746
1747         if (!safe_read8 (type, ptr, end))
1748                 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
1749
1750         if (type != 0x0A)
1751                 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
1752
1753         if (!safe_read_cint (count, ptr, end))
1754                 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
1755
1756         if (!count)
1757                 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
1758
1759         for (i = 0; i < count; ++i) {
1760                 if (!parse_type (ctx, &ptr, end))
1761                         FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
1762         }
1763         return TRUE;
1764 }
1765
1766 static gboolean
1767 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
1768 {
1769         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1770         guint32 entry_size, bytes;
1771
1772         if (blob.size < offset)
1773                 return FALSE;
1774
1775         if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1776                 return FALSE;
1777
1778         if (entry_size < minsize)
1779                 return FALSE;
1780
1781         if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
1782                 return FALSE;
1783         entry_size += bytes;
1784
1785         return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
1786 }
1787
1788 static gboolean
1789 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1790 {
1791         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1792         guint32 size, entry_size, bytes;
1793
1794         if (blob.size < offset)
1795                 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
1796         
1797         if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1798                 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
1799
1800         if (type == MONO_TYPE_STRING) {
1801                 //String is encoded as: compressed_int:len len *bytes
1802                 offset += bytes;
1803
1804                 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
1805                         FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));  
1806
1807                 return TRUE;
1808         }
1809
1810         switch (type) {
1811         case MONO_TYPE_BOOLEAN:
1812         case MONO_TYPE_I1:
1813         case MONO_TYPE_U1:
1814                 size = 1;
1815                 break;
1816         case MONO_TYPE_CHAR:
1817         case MONO_TYPE_I2:
1818         case MONO_TYPE_U2:
1819                 size = 2;
1820                 break;
1821         case MONO_TYPE_I4:
1822         case MONO_TYPE_U4:
1823         case MONO_TYPE_R4:
1824         case MONO_TYPE_CLASS:
1825                 size = 4;
1826                 break;
1827
1828         case MONO_TYPE_I8:
1829         case MONO_TYPE_U8:
1830         case MONO_TYPE_R8:
1831                 size = 8;
1832                 break;
1833         default:
1834                 g_assert_not_reached ();
1835         }
1836
1837         if (size != entry_size)
1838                 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
1839
1840         offset += bytes;
1841
1842         if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
1843                 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
1844
1845         if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
1846                 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
1847         return TRUE;
1848 }
1849
1850 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
1851 //only 0x01, 0x40 and 0x80 are allowed
1852 #define SECTION_HEADER_INVALID_FLAGS 0x3E
1853
1854 static gboolean
1855 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1856 {
1857         unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
1858         unsigned header = 0;
1859         unsigned fat_header = 0, size = 0, max_stack;
1860         const char *ptr = NULL, *end;
1861
1862         if (offset == INVALID_ADDRESS)
1863                 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
1864
1865         ptr = ctx->data + offset;
1866         end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
1867
1868         if (!safe_read8 (header, ptr, end))
1869                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
1870
1871         switch (header & 0x3) {
1872         case 0:
1873         case 1:
1874                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
1875         case 2:
1876                 header >>= 2;
1877                 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end)) 
1878                         FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
1879                 return TRUE;
1880         }
1881         //FAT HEADER
1882         --ptr;
1883         if (!safe_read16 (fat_header, ptr, end))
1884                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
1885
1886         size = (fat_header >> 12) & 0xF;
1887         if (size != 3)
1888                 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
1889
1890         if (!safe_read16 (max_stack, ptr, end))
1891                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
1892
1893         if (!safe_read32 (code_size, ptr, end))
1894                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
1895
1896         if (!safe_read32 (local_vars_tok, ptr, end))
1897                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
1898
1899         if (local_vars_tok) {
1900                 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
1901                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
1902                 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)   
1903                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
1904         }
1905
1906         if (fat_header & FAT_HEADER_INVALID_FLAGS)
1907                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
1908
1909         if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
1910                 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
1911
1912         if (!(fat_header & 0x08))
1913                 return TRUE;
1914
1915         ptr += code_size;
1916
1917         do {
1918                 unsigned section_header = 0, section_size = 0;
1919                 gboolean is_fat;
1920
1921                 ptr = dword_align (ptr);
1922                 if (!safe_read32 (section_header, ptr, end))
1923                         FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
1924
1925                 if (section_header & SECTION_HEADER_INVALID_FLAGS)
1926                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
1927                         
1928                 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
1929                 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
1930
1931                 if (section_size < 4)
1932                         FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
1933
1934                 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
1935                         FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
1936
1937                 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
1938                         guint32 i, clauses = section_size / (is_fat ? 24 : 12);
1939                         /*
1940                                 LAMEIMPL: MS emits section_size without accounting for header size.
1941                                 Mono does as the spec says. section_size is header + section
1942                                 MS's peverify happily accepts both. 
1943                         */
1944                         if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
1945                                 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)));
1946
1947                         /* only verify the class token is verified as the rest is done by the IL verifier*/
1948                         for (i = 0; i < clauses; ++i) {
1949                                 unsigned flags = *(unsigned char*)ptr;
1950                                 unsigned class_token = 0;
1951                                 ptr += (is_fat ? 20 : 8);
1952                                 if (!safe_read32 (class_token, ptr, end))
1953                                         FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
1954                                 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
1955                                         guint table = mono_metadata_token_table (class_token);
1956                                         if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
1957                                                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
1958                                         if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
1959                                                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
1960                                 }
1961                         }
1962                 }
1963
1964                 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
1965                         break;
1966         } while (1);
1967         return TRUE;
1968 }
1969
1970 static void
1971 verify_module_table (VerifyContext *ctx)
1972 {
1973         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1974         guint32 data [MONO_MODULE_SIZE];
1975
1976         if (table->rows != 1)
1977                 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1978
1979         mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1980
1981         if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1982                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1983
1984         if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1985                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1986
1987         if (data [MONO_MODULE_ENC] != 0)
1988                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1989
1990         if (data [MONO_MODULE_ENCBASE] != 0)
1991                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1992 }
1993
1994 static void
1995 verify_typeref_table (VerifyContext *ctx)
1996 {
1997         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1998         guint32 data [MONO_TYPEREF_SIZE];
1999         int i;
2000
2001         for (i = 0; i < table->rows; ++i) {
2002                 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
2003                 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
2004                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
2005                 
2006                 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
2007                         ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
2008
2009                 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
2010                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
2011
2012                 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2013                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
2014         }
2015 }
2016
2017 /*bits 9,11,14,15,19,21,24-31 */
2018 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2019 static void
2020 verify_typedef_table (VerifyContext *ctx)
2021 {
2022         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2023         guint32 data [MONO_TYPEDEF_SIZE];
2024         guint32 fieldlist = 1, methodlist = 1, visibility;
2025         int i;
2026
2027         if (table->rows == 0)
2028                 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2029
2030         for (i = 0; i < table->rows; ++i) {
2031                 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2032                 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2033                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2034
2035                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2036                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2037
2038                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2039                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2040
2041                 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2042                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2043
2044                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2045                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2046
2047                 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2048                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2049
2050                 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2051                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2052
2053                 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2054                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2055
2056                 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2057                 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2058                         search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2059                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2060
2061                 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2062                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2063
2064                 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2065                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2066
2067                 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2068                         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));
2069
2070                 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2071                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2072
2073                 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2074                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2075
2076                 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2077                         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));
2078
2079                 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2080                 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2081         }
2082 }
2083
2084 static void
2085 verify_typedef_table_full (VerifyContext *ctx)
2086 {
2087         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2088         guint32 data [MONO_TYPEDEF_SIZE];
2089         int i;
2090
2091         if (table->rows == 0)
2092                 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2093
2094         for (i = 0; i < table->rows; ++i) {
2095                 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2096
2097                 if (i == 0) {
2098                         if (data [MONO_TYPEDEF_EXTENDS] != 0)
2099                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2100                         continue;
2101                 }
2102
2103                 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2104                         if (data [MONO_TYPEDEF_EXTENDS])
2105                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2106                 } else {
2107                         gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2108                         gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2109
2110                         if (is_sys_obj) {
2111                                 if (has_parent)
2112                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2113                         } else {
2114                                 if (!has_parent) {
2115                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2116                                 }
2117                         }
2118                 }
2119         }
2120 }
2121
2122 /*bits 3,11,14 */
2123 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2124 static void
2125 verify_field_table (VerifyContext *ctx)
2126 {
2127         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2128         guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2129         int i;
2130
2131         module_field_list = (guint32)-1;
2132         if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2133                 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2134                 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2135         }
2136         
2137         for (i = 0; i < table->rows; ++i) {
2138                 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2139                 flags = data [MONO_FIELD_FLAGS];
2140
2141                 if (flags & INVALID_FIELD_FLAG_BITS)
2142                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2143
2144                 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)         
2145                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2146
2147                 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2148                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2149
2150                 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2151                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2152
2153                 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2154                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2155
2156                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2157                                 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2158                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2159
2160                 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2161                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2162                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2163
2164                 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2165                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2166                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2167
2168                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2169                                 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2170                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2171
2172                 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2173                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2174
2175                 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2176                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2177
2178                 //TODO verify contant flag
2179
2180                 if (i + 1 < module_field_list) {
2181                         guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2182                         if (!(flags & FIELD_ATTRIBUTE_STATIC))
2183                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2184                         if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2185                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2186                 }
2187         }
2188 }
2189
2190 static void
2191 verify_field_table_full (VerifyContext *ctx)
2192 {
2193         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2194         guint32 data [MONO_FIELD_SIZE];
2195         int i;
2196         
2197         for (i = 0; i < table->rows; ++i) {
2198                 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2199
2200                 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2201                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2202         }
2203 }
2204
2205 /*bits 6,8,9,10,11,13,14,15*/
2206 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2207 static void
2208 verify_method_table (VerifyContext *ctx)
2209 {
2210         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2211         guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2212         guint32 paramlist = 1;
2213         gboolean is_ctor, is_cctor;
2214         const char *name;
2215         int i;
2216
2217         module_method_list = (guint32)-1;
2218         if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2219                 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2220                 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2221         }
2222
2223         for (i = 0; i < table->rows; ++i) {
2224                 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2225                 rva = data [MONO_METHOD_RVA];
2226                 implflags = data [MONO_METHOD_IMPLFLAGS];
2227                 flags = data [MONO_METHOD_FLAGS];
2228                 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2229                 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2230                 
2231
2232                 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2233                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2234
2235                 if (access == 0x7)
2236                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2237
2238                 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2239                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2240
2241                 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2242                 is_ctor = !strcmp (".ctor", name);
2243                 is_cctor = !strcmp (".cctor", name);
2244
2245                 if ((is_ctor || is_cctor) &&
2246                         search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2247                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2248
2249                 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2250                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2251                 
2252                 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2253                         if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2254                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2255                         if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2256                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2257                 }
2258
2259                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2260                         ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2261
2262                 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2263                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2264
2265                 //XXX no checks against cas stuff 10,11,12,13)
2266
2267                 //TODO check iface with .ctor (15,16)
2268
2269                 if (i + 1 < module_method_list) {
2270                         if (!(flags & METHOD_ATTRIBUTE_STATIC))
2271                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2272                         if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2273                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2274                         if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2275                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2276                 }
2277
2278                 //TODO check valuetype for synchronized
2279
2280                 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2281                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2282
2283                 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2284                         if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2285                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2286                         if (!(flags & METHOD_ATTRIBUTE_STATIC))
2287                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2288                 }
2289
2290                 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && 
2291                                 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2292                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2293
2294                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2295                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2296
2297                 //TODO check signature contents
2298
2299                 if (rva) {
2300                         if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2301                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2302                         if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2303                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2304                 } else {
2305                         if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2306                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2307                 }
2308
2309                 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2310                         if (rva)
2311                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2312                         if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2313                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2314                 }
2315                 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2316                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2317
2318                 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2319                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2320
2321                 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2322                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2323
2324                 if (data [MONO_METHOD_PARAMLIST] == 0)
2325                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2326
2327                 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2328                         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));
2329
2330                 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2331                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2332
2333                 paramlist = data [MONO_METHOD_PARAMLIST];
2334
2335         }
2336 }
2337
2338 static void
2339 verify_method_table_full (VerifyContext *ctx)
2340 {
2341         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2342         guint32 data [MONO_METHOD_SIZE], rva;
2343         int i;
2344
2345         for (i = 0; i < table->rows; ++i) {
2346                 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2347                 rva = data [MONO_METHOD_RVA];
2348
2349                 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2350                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2351
2352                 if (rva && !is_valid_method_header (ctx, rva))
2353                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2354         }
2355 }
2356
2357 static guint32
2358 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2359 {
2360         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2361         guint32 row = *current_method;
2362         guint32 paramlist, tmp;
2363
2364
2365         paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2366         while (row < table->rows) {
2367                 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2368                 if (tmp > paramlist) {
2369                         *current_method = row;
2370                         return tmp - paramlist;
2371                 }
2372                 ++row;
2373         }
2374
2375         /*no more methods, all params apply to the last one*/
2376         *current_method = table->rows;
2377         return (guint32)-1;
2378 }
2379
2380
2381 #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))
2382 static void
2383 verify_param_table (VerifyContext *ctx)
2384 {
2385         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2386         guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2387         gboolean first_param = TRUE;
2388         int i;
2389
2390         if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2391                 if (table->rows > 0)
2392                         ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2393                 return;
2394         }
2395         
2396         remaining_params = get_next_param_count (ctx, &current_method);
2397
2398         for (i = 0; i < table->rows; ++i) {
2399                 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2400                 flags = data [MONO_PARAM_FLAGS];
2401
2402                 if (flags & INVALID_PARAM_FLAGS_BITS)
2403                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2404
2405                 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2406                         if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2407                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2408                 } else {
2409                         if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2410                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2411                 }
2412
2413                 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)
2414                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2415
2416                 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2417                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2418
2419                 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2420                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2421
2422                 first_param = FALSE;
2423                 sequence = data [MONO_PARAM_SEQUENCE];
2424                 if (--remaining_params == 0) {
2425                         remaining_params = get_next_param_count (ctx, &current_method);
2426                         first_param = TRUE;
2427                 }
2428         }
2429 }
2430
2431 static void
2432 verify_interfaceimpl_table (VerifyContext *ctx)
2433 {
2434         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2435         guint32 data [MONO_INTERFACEIMPL_SIZE];
2436         int i;
2437
2438         for (i = 0; i < table->rows; ++i) {
2439                 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2440                 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2441                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2442
2443                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2444                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2445
2446                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2447                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2448         }
2449 }
2450
2451 static void
2452 verify_memberref_table (VerifyContext *ctx)
2453 {
2454         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2455         guint32 data [MONO_MEMBERREF_SIZE];
2456         int i;
2457
2458         for (i = 0; i < table->rows; ++i) {
2459                 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2460
2461                 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2462                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2463
2464                 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2465                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2466
2467                 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2468                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2469
2470                 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2471                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2472         }
2473 }
2474
2475
2476 static void
2477 verify_memberref_table_full (VerifyContext *ctx)
2478 {
2479         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2480         guint32 data [MONO_MEMBERREF_SIZE];
2481         int i;
2482
2483         for (i = 0; i < table->rows; ++i) {
2484                 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2485
2486                 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2487                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field  0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2488         }
2489 }
2490
2491 static void
2492 verify_constant_table (VerifyContext *ctx)
2493 {
2494         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2495         guint32 data [MONO_CONSTANT_SIZE], type;
2496         int i;
2497
2498         for (i = 0; i < table->rows; ++i) {
2499                 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2500                 type = data [MONO_CONSTANT_TYPE];
2501
2502                 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2503                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2504
2505                 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2506                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2507
2508                 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2509                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2510
2511                 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2512                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2513         }
2514 }
2515
2516 static void
2517 verify_cattr_table (VerifyContext *ctx)
2518 {
2519         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2520         guint32 data [MONO_CUSTOM_ATTR_SIZE];
2521         int i;
2522
2523         for (i = 0; i < table->rows; ++i) {
2524                 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2525
2526                 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2527                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2528
2529                 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2530                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2531
2532                 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2533                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2534         }
2535 }
2536
2537 static void
2538 verify_cattr_table_full (VerifyContext *ctx)
2539 {
2540         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2541         guint32 data [MONO_CUSTOM_ATTR_SIZE];
2542         int i;
2543
2544         for (i = 0; i < table->rows; ++i) {
2545                 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2546
2547                 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2548                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2549         }
2550 }
2551
2552 static void
2553 verify_field_marshal_table (VerifyContext *ctx)
2554 {
2555         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2556         guint32 data [MONO_FIELD_MARSHAL_SIZE];
2557         int i;
2558
2559         for (i = 0; i < table->rows; ++i) {
2560                 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2561
2562                 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2563                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2564
2565                 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2566                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2567
2568                 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2569                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2570
2571                 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2572                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2573         }
2574 }
2575
2576 static void
2577 verify_field_marshal_table_full (VerifyContext *ctx)
2578 {
2579         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2580         guint32 data [MONO_FIELD_MARSHAL_SIZE];
2581         int i;
2582
2583         for (i = 0; i < table->rows; ++i) {
2584                 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2585
2586                 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2587                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2588         }
2589 }
2590
2591 static void
2592 verify_decl_security_table (VerifyContext *ctx)
2593 {
2594         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2595         guint32 data [MONO_DECL_SECURITY_SIZE];
2596         int i;
2597
2598         for (i = 0; i < table->rows; ++i) {
2599                 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2600
2601                 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2602                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2603
2604                 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2605                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2606
2607                 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2608                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2609         }
2610 }
2611
2612 static void
2613 verify_decl_security_table_full (VerifyContext *ctx)
2614 {
2615         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2616         guint32 data [MONO_DECL_SECURITY_SIZE];
2617         int i;
2618
2619         for (i = 0; i < table->rows; ++i) {
2620                 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2621
2622                 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2623                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2624         }
2625 }
2626
2627 static void
2628 verify_class_layout_table (VerifyContext *ctx)
2629 {
2630         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2631         guint32 data [MONO_CLASS_LAYOUT_SIZE];
2632         int i;
2633
2634         for (i = 0; i < table->rows; ++i) {
2635                 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2636
2637                 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2638                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2639
2640                 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2641                 case 0:
2642                 case 1:
2643                 case 2:
2644                 case 4:
2645                 case 8:
2646                 case 16:
2647                 case 32:
2648                 case 64:
2649                 case 128:
2650                         break;
2651                 default:
2652                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2653                 }
2654         }
2655 }
2656
2657 static void
2658 verify_field_layout_table (VerifyContext *ctx)
2659 {
2660         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2661         guint32 data [MONO_FIELD_LAYOUT_SIZE];
2662         int i;
2663
2664         for (i = 0; i < table->rows; ++i) {
2665                 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2666
2667                 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2668                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2669         }
2670 }
2671
2672 static void
2673 verify_standalonesig_table (VerifyContext *ctx)
2674 {
2675         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2676         guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2677         int i;
2678
2679         for (i = 0; i < table->rows; ++i) {
2680                 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2681
2682                 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
2683                         ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2684         }
2685 }
2686
2687 static void
2688 verify_standalonesig_table_full (VerifyContext *ctx)
2689 {
2690         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2691         guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2692         int i;
2693
2694         for (i = 0; i < table->rows; ++i) {
2695                 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2696
2697                 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2698                         ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2699         }
2700 }
2701
2702 static void
2703 verify_eventmap_table (VerifyContext *ctx)
2704 {
2705         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2706         guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2707         int i;
2708
2709         for (i = 0; i < table->rows; ++i) {
2710                 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2711
2712                 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2713                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2714
2715                 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2716                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2717
2718                 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2719         }
2720 }
2721
2722 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2723 static void
2724 verify_event_table (VerifyContext *ctx)
2725 {
2726         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2727         guint32 data [MONO_EVENT_SIZE];
2728         int i;
2729
2730         for (i = 0; i < table->rows; ++i) {
2731                 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2732
2733                 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2734                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2735
2736                 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2737                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2738
2739                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2740                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2741         }
2742 }
2743
2744 static void
2745 verify_event_table_full (VerifyContext *ctx)
2746 {
2747         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2748         MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2749         guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2750         gboolean found_add, found_remove;
2751         int i, idx;
2752
2753         for (i = 0; i < table->rows; ++i) {
2754                 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2755
2756                 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2757                 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2758                 if (idx == -1)
2759                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2760
2761                 //first we move to the first row for this event
2762                 while (idx > 0) {
2763                         if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2764                                 break;
2765                         --idx;
2766                 }
2767                 //now move forward looking for AddOn and RemoveOn rows
2768                 found_add = found_remove = FALSE;
2769                 while (idx < sema_table->rows) {
2770                         mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2771                         if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2772                                 break;
2773                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2774                                 found_add = TRUE;
2775                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2776                                 found_remove = TRUE;
2777                         if (found_add && found_remove)
2778                                 break;
2779                         ++idx;
2780                 }
2781
2782                 if (!found_add)
2783                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2784                 if (!found_remove)
2785                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2786         }
2787 }
2788
2789 static void
2790 verify_propertymap_table (VerifyContext *ctx)
2791 {
2792         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2793         guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2794         int i;
2795
2796         for (i = 0; i < table->rows; ++i) {
2797                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2798
2799                 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2800                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2801
2802                 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2803                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2804
2805                 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2806         }
2807 }
2808
2809 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2810 static void
2811 verify_property_table (VerifyContext *ctx)
2812 {
2813         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2814         guint32 data [MONO_PROPERTY_SIZE];
2815         int i;
2816
2817         for (i = 0; i < table->rows; ++i) {
2818                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2819
2820                 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2821                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2822
2823                 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2824                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2825
2826                 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2827                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2828
2829                 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2830                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2831                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2832
2833         }
2834 }
2835
2836 static void
2837 verify_methodimpl_table (VerifyContext *ctx)
2838 {
2839         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2840         guint32 data [MONO_METHODIMPL_SIZE];
2841         int i;
2842
2843         for (i = 0; i < table->rows; ++i) {
2844                 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2845
2846                 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2847                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2848                         
2849                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2850                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2851                 
2852                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2853                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2854
2855                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2856                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2857                 
2858                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2859                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2860         }
2861 }
2862
2863 static void
2864 verify_moduleref_table (VerifyContext *ctx)
2865 {
2866         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2867         guint32 data [MONO_MODULEREF_SIZE];
2868         int i;
2869
2870         for (i = 0; i < table->rows; ++i) {
2871                 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2872
2873                 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2874                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2875         }
2876 }
2877
2878 static void
2879 verify_typespec_table (VerifyContext *ctx)
2880 {
2881         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2882         guint32 data [MONO_TYPESPEC_SIZE];
2883         int i;
2884
2885         for (i = 0; i < table->rows; ++i) {
2886                 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2887
2888                 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
2889                         ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2890         }
2891 }
2892
2893 static void
2894 verify_typespec_table_full (VerifyContext *ctx)
2895 {
2896         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2897         guint32 data [MONO_TYPESPEC_SIZE];
2898         int i;
2899
2900         for (i = 0; i < table->rows; ++i) {
2901                 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2902
2903                 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2904                         ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2905         }
2906 }
2907
2908 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
2909 static void
2910 verify_implmap_table (VerifyContext *ctx)
2911 {
2912         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2913         guint32 data [MONO_IMPLMAP_SIZE], cconv;
2914         int i;
2915
2916         for (i = 0; i < table->rows; ++i) {
2917                 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2918
2919                 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2920                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2921
2922                 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2923                 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2924                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2925
2926                 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2927                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2928
2929                 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2930                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2931
2932                 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2933                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2934
2935                 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2936                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2937
2938                 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
2939                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2940         }
2941 }
2942
2943 static void
2944 verify_fieldrva_table (VerifyContext *ctx)
2945 {
2946         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2947         guint32 data [MONO_FIELD_RVA_SIZE];
2948         int i;
2949
2950         for (i = 0; i < table->rows; ++i) {
2951                 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2952
2953                 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2954                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2955
2956                 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2957                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2958         }
2959 }
2960
2961 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
2962 static void
2963 verify_assembly_table (VerifyContext *ctx)
2964 {
2965         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2966         guint32 data [MONO_ASSEMBLY_SIZE], hash;
2967         int i;
2968
2969         if (table->rows > 1)
2970                 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2971
2972         for (i = 0; i < table->rows; ++i) {
2973                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2974
2975                 hash = data [MONO_ASSEMBLY_HASH_ALG];
2976                 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2977                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2978
2979                 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2980                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2981
2982                 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
2983                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2984
2985                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2986                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2987
2988                 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2989                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2990         }
2991 }
2992
2993 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2994 static void
2995 verify_assemblyref_table (VerifyContext *ctx)
2996 {
2997         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2998         guint32 data [MONO_ASSEMBLYREF_SIZE];
2999         int i;
3000
3001         for (i = 0; i < table->rows; ++i) {
3002                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3003
3004                 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3005                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3006
3007                 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3008                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3009
3010                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3011                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3012
3013                 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3014                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3015
3016                 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3017                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3018         }
3019 }
3020
3021 #define INVALID_FILE_FLAGS_BITS ~(1)
3022 static void
3023 verify_file_table (VerifyContext *ctx)
3024 {
3025         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3026         guint32 data [MONO_FILE_SIZE];
3027         int i;
3028
3029         for (i = 0; i < table->rows; ++i) {
3030                 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3031                 
3032                 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3033                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3034
3035                 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3036                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3037
3038                 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3039                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3040         }
3041 }
3042
3043 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3044 static void
3045 verify_exportedtype_table (VerifyContext *ctx)
3046 {
3047         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3048         guint32 data [MONO_EXP_TYPE_SIZE];
3049         int i;
3050
3051         for (i = 0; i < table->rows; ++i) {
3052                 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3053                 
3054                 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3055                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3056
3057                 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3058                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3059
3060                 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3061                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3062
3063                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3064                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3065
3066                 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3067                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3068
3069                 /*nested type can't have a namespace*/
3070                 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3071                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3072         }
3073 }
3074
3075 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3076 static void
3077 verify_manifest_resource_table (VerifyContext *ctx)
3078 {
3079         MonoCLIImageInfo *iinfo = ctx->image->image_info;
3080         MonoCLIHeader *ch = &iinfo->cli_cli_header;
3081         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3082         guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3083         int i;
3084
3085         resources_size = ch->ch_resources.size;
3086
3087         for (i = 0; i < table->rows; ++i) {
3088                 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3089
3090                 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3091                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3092
3093                 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3094                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3095
3096                 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3097                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3098
3099                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3100                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3101
3102                 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3103                 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3104
3105                 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3106                         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])));
3107
3108                 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3109                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3110
3111                 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3112                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3113         }
3114 }
3115
3116 static void
3117 verify_nested_class_table (VerifyContext *ctx)
3118 {
3119         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3120         guint32 data [MONO_NESTED_CLASS_SIZE];
3121         int i;
3122
3123         for (i = 0; i < table->rows; ++i) {
3124                 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3125
3126                 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3127                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3128                 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3129                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3130                 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3131                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass  and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3132         }
3133 }
3134
3135 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3136 static void
3137 verify_generic_param_table (VerifyContext *ctx)
3138 {
3139         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3140         guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3141         int i, param_number = 0;
3142
3143         for (i = 0; i < table->rows; ++i) {
3144                 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3145
3146                 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3147                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3148
3149                 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3150                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3151
3152                 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3153                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3154
3155                 token = data [MONO_GENERICPARAM_OWNER];
3156
3157                 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3158                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3159
3160                 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3161                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3162
3163                 if (token != last_token) {
3164                         param_number = 0;
3165                         last_token = token;
3166                 }
3167
3168                 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3169                         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));
3170
3171                 ++param_number;
3172         }
3173 }
3174
3175 static void
3176 verify_method_spec_table (VerifyContext *ctx)
3177 {
3178         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3179         guint32 data [MONO_METHODSPEC_SIZE];
3180         int i;
3181
3182         for (i = 0; i < table->rows; ++i) {
3183                 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3184
3185                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3186                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3187
3188                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3189                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3190
3191                 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3192                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3193         }
3194 }
3195
3196 static void
3197 verify_method_spec_table_full (VerifyContext *ctx)
3198 {
3199         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3200         guint32 data [MONO_METHODSPEC_SIZE];
3201         int i;
3202
3203         for (i = 0; i < table->rows; ++i) {
3204                 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3205
3206                 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3207                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3208         }
3209 }
3210
3211 static void
3212 verify_generic_param_constraint_table (VerifyContext *ctx)
3213 {
3214         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3215         guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3216         int i;
3217
3218         for (i = 0; i < table->rows; ++i) {
3219                 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3220
3221                 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3222                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3223
3224                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3225                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3226
3227                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3228                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3229         }
3230 }
3231
3232
3233 typedef struct {
3234         const char *name;
3235         const char *name_space;
3236         guint32 resolution_scope;
3237 } TypeDefUniqueId;
3238
3239 static guint
3240 typedef_hash (gconstpointer _key)
3241 {
3242         const TypeDefUniqueId *key = _key;
3243         return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3244 }
3245
3246 static gboolean
3247 typedef_equals (gconstpointer _a, gconstpointer _b)
3248 {
3249         const TypeDefUniqueId *a = _a;
3250         const TypeDefUniqueId *b = _b;
3251         return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3252 }
3253
3254 static void
3255 verify_typedef_table_global_constraints (VerifyContext *ctx)
3256 {
3257         int i;
3258         guint32 data [MONO_TYPEDEF_SIZE];
3259         guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3260         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3261         MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3262         GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3263
3264         for (i = 0; i < table->rows; ++i) {
3265                 guint visibility;
3266                 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3267                 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3268
3269                 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3270                 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3271                 type->resolution_scope = 0;
3272
3273                 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3274                 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3275                         int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3276                         g_assert (res >= 0);
3277
3278                         mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3279                         type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3280                 }
3281
3282                 if (g_hash_table_lookup (unique_types, type)) {
3283                         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));
3284                         g_hash_table_destroy (unique_types);
3285                         g_free (type);
3286                         return;
3287                 }
3288                 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3289         }
3290
3291         g_hash_table_destroy (unique_types);
3292 }
3293
3294 static void
3295 verify_typeref_table_global_constraints (VerifyContext *ctx)
3296 {
3297         int i;
3298         guint32 data [MONO_TYPEREF_SIZE];
3299         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3300         GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3301
3302         for (i = 0; i < table->rows; ++i) {
3303                 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3304                 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3305
3306                 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3307                 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3308                 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3309
3310                 if (g_hash_table_lookup (unique_types, type)) {
3311                         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));
3312                         g_hash_table_destroy (unique_types);
3313                         g_free (type);
3314                         return;
3315                 }
3316                 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3317         }
3318
3319         g_hash_table_destroy (unique_types);
3320 }
3321
3322 static void
3323 verify_tables_data_global_constraints (VerifyContext *ctx)
3324 {
3325         verify_typeref_table_global_constraints (ctx);
3326         CHECK_ERROR ();
3327         verify_typedef_table_global_constraints (ctx);
3328 }
3329         
3330 static void
3331 verify_tables_data (VerifyContext *ctx)
3332 {
3333         OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3334         guint32 size = 0, tables_offset;
3335         int i;
3336
3337         for (i = 0; i < 0x2D; ++i) {
3338                 MonoTableInfo *table = &ctx->image->tables [i];
3339                 guint32 tmp_size;
3340                 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3341                 if (tmp_size < size) {
3342                         size = 0;
3343                         break;
3344                 }
3345                 size = tmp_size;                        
3346         }
3347
3348         if (size == 0)
3349                 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3350
3351         tables_offset = ctx->image->tables_base - ctx->data;
3352         if (!bounds_check_offset (&tables_area, tables_offset, size))
3353                 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)));
3354
3355         verify_module_table (ctx);
3356         CHECK_ERROR ();
3357         verify_typeref_table (ctx);
3358         CHECK_ERROR ();
3359         verify_typedef_table (ctx);
3360         CHECK_ERROR ();
3361         verify_field_table (ctx);
3362         CHECK_ERROR ();
3363         verify_method_table (ctx);
3364         CHECK_ERROR ();
3365         verify_param_table (ctx);
3366         CHECK_ERROR ();
3367         verify_interfaceimpl_table (ctx);
3368         CHECK_ERROR ();
3369         verify_memberref_table (ctx);
3370         CHECK_ERROR ();
3371         verify_constant_table (ctx);
3372         CHECK_ERROR ();
3373         verify_cattr_table (ctx);
3374         CHECK_ERROR ();
3375         verify_field_marshal_table (ctx);
3376         CHECK_ERROR ();
3377         verify_decl_security_table (ctx);
3378         CHECK_ERROR ();
3379         verify_class_layout_table (ctx);
3380         CHECK_ERROR ();
3381         verify_field_layout_table (ctx);
3382         CHECK_ERROR ();
3383         verify_standalonesig_table (ctx);
3384         CHECK_ERROR ();
3385         verify_eventmap_table (ctx);
3386         CHECK_ERROR ();
3387         verify_event_table (ctx);
3388         CHECK_ERROR ();
3389         verify_propertymap_table (ctx);
3390         CHECK_ERROR ();
3391         verify_property_table (ctx);
3392         CHECK_ERROR ();
3393         verify_methodimpl_table (ctx);
3394         CHECK_ERROR ();
3395         verify_moduleref_table (ctx);
3396         CHECK_ERROR ();
3397         verify_typespec_table (ctx);
3398         CHECK_ERROR ();
3399         verify_implmap_table (ctx);
3400         CHECK_ERROR ();
3401         verify_fieldrva_table (ctx);
3402         CHECK_ERROR ();
3403         verify_assembly_table (ctx);
3404         CHECK_ERROR ();
3405         verify_assemblyref_table (ctx);
3406         CHECK_ERROR ();
3407         verify_file_table (ctx);
3408         CHECK_ERROR ();
3409         verify_exportedtype_table (ctx);
3410         CHECK_ERROR ();
3411         verify_manifest_resource_table (ctx);
3412         CHECK_ERROR ();
3413         verify_nested_class_table (ctx);
3414         CHECK_ERROR ();
3415         verify_generic_param_table (ctx);
3416         CHECK_ERROR ();
3417         verify_method_spec_table (ctx);
3418         CHECK_ERROR ();
3419         verify_generic_param_constraint_table (ctx);
3420         CHECK_ERROR ();
3421         verify_tables_data_global_constraints (ctx);
3422 }
3423
3424 static void
3425 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
3426 {
3427         memset (ctx, 0, sizeof (VerifyContext));
3428         ctx->image = image;
3429         ctx->report_error = error_list != NULL;
3430         ctx->report_warning = FALSE; //export this setting in the API
3431         ctx->valid = 1;
3432         ctx->size = image->raw_data_len;
3433         ctx->data = image->raw_data;
3434 }
3435
3436 static gboolean
3437 cleanup_context (VerifyContext *ctx, GSList **error_list)
3438 {
3439         g_free (ctx->sections);
3440         if (error_list)
3441                 *error_list = ctx->errors;
3442         else
3443                 mono_free_verify_list (ctx->errors);
3444         return ctx->valid;      
3445 }
3446
3447 gboolean
3448 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3449 {
3450         VerifyContext ctx;
3451
3452         if (!mono_verifier_is_enabled_for_image (image))
3453                 return TRUE;
3454
3455         init_verify_context (&ctx, image, error_list);
3456         ctx.stage = STAGE_PE;
3457
3458         verify_msdos_header (&ctx);
3459         CHECK_STATE();
3460         verify_pe_header (&ctx);
3461         CHECK_STATE();
3462         verify_pe_optional_header (&ctx);
3463         CHECK_STATE();
3464         load_section_table (&ctx);
3465         CHECK_STATE();
3466         load_data_directories (&ctx);
3467         CHECK_STATE();
3468         verify_import_table (&ctx);
3469         CHECK_STATE();
3470         /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3471         verify_resources_table (&ctx);
3472
3473 cleanup:
3474         return cleanup_context (&ctx, error_list);
3475 }
3476
3477 gboolean
3478 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3479 {
3480         VerifyContext ctx;
3481
3482         if (!mono_verifier_is_enabled_for_image (image))
3483                 return TRUE;
3484
3485         init_verify_context (&ctx, image, error_list);
3486         ctx.stage = STAGE_CLI;
3487
3488         verify_cli_header (&ctx);
3489         CHECK_STATE();
3490         verify_metadata_header (&ctx);
3491         CHECK_STATE();
3492         verify_tables_schema (&ctx);
3493
3494 cleanup:
3495         return cleanup_context (&ctx, error_list);
3496 }
3497
3498
3499 /*
3500  * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3501  * Other verification checks are meant to be done lazily by the runtime. Those include:
3502  *      blob items (signatures, method headers, custom attributes, etc)
3503  *  type semantics related
3504  *  vtable related
3505  *  stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3506  * 
3507  * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3508  * operation still need more checking.
3509  */
3510 gboolean
3511 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3512 {
3513         VerifyContext ctx;
3514
3515         if (!mono_verifier_is_enabled_for_image (image))
3516                 return TRUE;
3517
3518         init_verify_context (&ctx, image, error_list);
3519         ctx.stage = STAGE_TABLES;
3520
3521         verify_tables_data (&ctx);
3522
3523         return cleanup_context (&ctx, error_list);
3524 }
3525
3526
3527 /*
3528  * Verifies all other constraints.
3529  */
3530 gboolean
3531 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3532 {
3533         VerifyContext ctx;
3534
3535         if (!mono_verifier_is_enabled_for_image (image))
3536                 return TRUE;
3537
3538         init_verify_context (&ctx, image, error_list);
3539         ctx.stage = STAGE_TABLES;
3540
3541         verify_typedef_table_full (&ctx);
3542         CHECK_STATE ();
3543         verify_field_table_full (&ctx);
3544         CHECK_STATE ();
3545         verify_method_table_full (&ctx);
3546         CHECK_STATE ();
3547         verify_memberref_table_full (&ctx);
3548         CHECK_STATE ();
3549         verify_cattr_table_full (&ctx);
3550         CHECK_STATE ();
3551         verify_field_marshal_table_full (&ctx);
3552         CHECK_STATE ();
3553         verify_decl_security_table_full (&ctx);
3554         CHECK_STATE ();
3555         verify_standalonesig_table_full (&ctx);
3556         CHECK_STATE ();
3557         verify_event_table_full (&ctx);
3558         CHECK_STATE ();
3559         verify_typespec_table_full (&ctx);
3560         CHECK_STATE ();
3561         verify_method_spec_table_full (&ctx);
3562
3563 cleanup:
3564         return cleanup_context (&ctx, error_list);
3565 }
3566
3567 gboolean
3568 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3569 {
3570         VerifyContext ctx;
3571
3572         if (!mono_verifier_is_enabled_for_image (image))
3573                 return TRUE;
3574
3575         init_verify_context (&ctx, image, error_list);
3576         ctx.stage = STAGE_TABLES;
3577
3578         is_valid_field_signature (&ctx, offset);
3579         return cleanup_context (&ctx, error_list);
3580 }
3581
3582 gboolean
3583 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3584 {
3585         VerifyContext ctx;
3586
3587         if (!mono_verifier_is_enabled_for_image (image))
3588                 return TRUE;
3589
3590         init_verify_context (&ctx, image, error_list);
3591         ctx.stage = STAGE_TABLES;
3592
3593         is_valid_method_header (&ctx, offset);
3594         return cleanup_context (&ctx, error_list);
3595 }
3596
3597 gboolean
3598 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3599 {
3600         VerifyContext ctx;
3601
3602         if (!mono_verifier_is_enabled_for_image (image))
3603                 return TRUE;
3604
3605         init_verify_context (&ctx, image, error_list);
3606         ctx.stage = STAGE_TABLES;
3607
3608         is_valid_method_signature (&ctx, offset);
3609         return cleanup_context (&ctx, error_list);
3610 }
3611
3612 gboolean
3613 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3614 {
3615         VerifyContext ctx;
3616
3617         if (!mono_verifier_is_enabled_for_image (image))
3618                 return TRUE;
3619
3620         init_verify_context (&ctx, image, error_list);
3621         ctx.stage = STAGE_TABLES;
3622
3623         is_valid_method_or_field_signature (&ctx, offset);
3624         return cleanup_context (&ctx, error_list);
3625 }
3626
3627 gboolean
3628 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3629 {
3630         VerifyContext ctx;
3631
3632         if (!mono_verifier_is_enabled_for_image (image))
3633                 return TRUE;
3634
3635         init_verify_context (&ctx, image, error_list);
3636         ctx.stage = STAGE_TABLES;
3637
3638         is_valid_standalonesig_blob (&ctx, offset);
3639         return cleanup_context (&ctx, error_list);
3640 }
3641
3642 gboolean
3643 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3644 {
3645         VerifyContext ctx;
3646
3647         if (!mono_verifier_is_enabled_for_image (image))
3648                 return TRUE;
3649
3650         init_verify_context (&ctx, image, error_list);
3651         ctx.stage = STAGE_TABLES;
3652
3653         is_valid_typespec_blob (&ctx, offset);
3654         return cleanup_context (&ctx, error_list);
3655 }
3656
3657 gboolean
3658 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3659 {
3660         VerifyContext ctx;
3661
3662         if (!mono_verifier_is_enabled_for_image (image))
3663                 return TRUE;
3664
3665         init_verify_context (&ctx, image, error_list);
3666         ctx.stage = STAGE_TABLES;
3667
3668         is_valid_methodspec_blog (&ctx, offset);
3669         return cleanup_context (&ctx, error_list);
3670 }
3671
3672 #else
3673 gboolean
3674 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3675 {
3676         return TRUE;
3677 }
3678
3679 gboolean
3680 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3681 {
3682         return TRUE;
3683 }
3684
3685 gboolean
3686 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3687 {
3688         return TRUE;
3689 }
3690
3691 gboolean
3692 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3693 {
3694         return TRUE;
3695 }
3696
3697 gboolean
3698 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3699 {
3700         return TRUE;
3701 }
3702
3703 gboolean
3704 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3705 {
3706         return TRUE;
3707 }
3708
3709 gboolean
3710 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3711 {
3712         return TRUE;
3713 }
3714
3715 gboolean
3716 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3717 {
3718         return TRUE;
3719 }
3720
3721 gboolean
3722 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3723 {
3724         return TRUE;
3725 }
3726
3727 gboolean
3728 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3729 {
3730         return TRUE;
3731 }
3732
3733 gboolean
3734 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3735 {
3736         return TRUE;
3737 }
3738
3739 #endif /* DISABLE_VERIFIER */