6d8ea84f19cccf78544ca149327f0de73bc9f427
[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 verifier doesn't support MS specific table %x", i));
885                 if (i == 0x1E || i == 0x1F || i >= 0x2D)
886                         ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
887                 ++count;
888         }
889
890         if (tables_area.size < 24 + count * 4)
891                 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for decoding row counts (requires %d bytes)", tables_area.size, 24 + count * 4));
892         ptr += 24;
893
894         for (i = 0; i < 64; ++i) {
895                 if (valid_tables & ((guint64)1 << i)) {
896                         guint32 row_count = read32 (ptr);
897                         if (row_count > (1 << 24) - 1)
898                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
899                         ptr += 4;
900                 }
901         }
902 }
903
904 /*----------nothing from here on can use data_directory or metadata_streams ---*/
905
906 static guint32
907 get_col_offset (VerifyContext *ctx, int table, int column)
908 {
909         guint32 bitfield = ctx->image->tables [table].size_bitfield;
910         guint32 offset = 0;
911
912         while (column-- > 0)
913                 offset += mono_metadata_table_size (bitfield, column);
914
915         return offset;
916 }
917
918 static guint32
919 get_col_size (VerifyContext *ctx, int table, int column)
920 {
921         return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
922 }
923
924 static OffsetAndSize
925 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
926 {
927         OffsetAndSize res;
928         res.offset = header->data - ctx->data;
929         res.size = header->size;
930
931         return res;
932 }
933
934 static gboolean
935 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
936 {
937         OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
938         glong length;
939         const char *data = ctx->data + strings.offset;
940
941         if (offset >= strings.size)
942                 return FALSE;
943         if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing  
944                 return FALSE;
945
946         if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
947                 return FALSE;
948         return allow_empty || length > 0;
949 }
950
951 static gboolean
952 is_valid_string (VerifyContext *ctx, guint32 offset)
953 {
954         return is_valid_string_full (ctx, offset, TRUE);
955 }
956
957 static gboolean
958 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
959 {
960         return is_valid_string_full (ctx, offset, FALSE);
961 }
962
963 static gboolean
964 is_valid_guid (VerifyContext *ctx, guint32 offset)
965 {
966         OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
967         return guids.size >= 8 && guids.size - 8 >= offset;
968 }
969
970 static guint32
971 get_coded_index_token (int token_kind, guint32 coded_token)
972 {
973         guint32 bits = coded_index_desc [token_kind];
974         return coded_token >> bits;
975 }
976
977 static guint32
978 get_coded_index_table (int kind, guint32 coded_token)
979 {
980         guint32 idx, bits = coded_index_desc [kind];
981         kind += 2;
982         idx = coded_token & ((1 << bits) - 1);
983         return coded_index_desc [kind + idx];
984 }
985
986 static guint32
987 make_coded_token (int kind, guint32 table, guint32 table_idx)
988 {
989         guint32 bits = coded_index_desc [kind++];
990         guint32 tables = coded_index_desc [kind++];
991         guint32 i;
992         for (i = 0; i < tables; ++i) {
993                 if (coded_index_desc [kind++] == table)
994                         return ((table_idx + 1) << bits) | i; 
995         }
996         g_assert_not_reached ();
997         return -1;
998 }
999
1000 static gboolean
1001 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
1002 {
1003         guint32 bits = coded_index_desc [token_kind++];
1004         guint32 table_count = coded_index_desc [token_kind++];
1005         guint32 table = coded_token & ((1 << bits) - 1);
1006         guint32 token = coded_token >> bits;
1007
1008         if (table >= table_count)
1009                 return FALSE;
1010
1011         /*token_kind points to the first table idx*/
1012         table = coded_index_desc [token_kind + table];
1013
1014         if (table == INVALID_TABLE)
1015                 return FALSE;
1016         return token <= ctx->image->tables [table].rows;
1017 }
1018
1019 typedef struct {
1020         guint32 token;
1021         guint32 col_size;
1022         guint32 col_offset;
1023         MonoTableInfo *table;
1024 } RowLocator;
1025
1026 static int
1027 token_locator (const void *a, const void *b)
1028 {
1029         RowLocator *loc = (RowLocator *)a;
1030         unsigned const char *row = (unsigned const char *)b;
1031         guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1032
1033         VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1034         return (int)loc->token - (int)token;
1035 }
1036
1037 static int
1038 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1039 {
1040         MonoTableInfo *tinfo = &ctx->image->tables [table];
1041         RowLocator locator;
1042         const char *res, *base;
1043         locator.token = coded_token;
1044         locator.col_offset = get_col_offset (ctx, table, column);
1045         locator.col_size = get_col_size (ctx, table, column);
1046         locator.table = tinfo;
1047
1048         base = tinfo->base;
1049
1050         VERIFIER_DEBUG ( printf ("looking token %x table %d col %d rsize %d roff %d\n", coded_token, table, column, locator.col_size, locator.col_offset) );
1051         res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1052         if (!res)
1053                 return -1;
1054
1055         return (res - base) / tinfo->row_size;
1056 }
1057
1058 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1059 static const char*
1060 get_string_ptr (VerifyContext *ctx, guint offset)
1061 {
1062         return ctx->image->heap_strings.data + offset;
1063 }
1064
1065 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1066 static int
1067 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1068 {
1069         if (offset == 0)
1070                 return strcmp (str, "");
1071
1072         return strcmp (str, get_string_ptr (ctx, offset));
1073 }
1074
1075 static gboolean
1076 mono_verifier_is_corlib (MonoImage *image)
1077 {
1078         gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ? 
1079                         TRUE : mono_security_core_clr_is_platform_image (image);
1080
1081         return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1082 }
1083
1084 static gboolean
1085 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1086 {
1087         return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1088 }
1089
1090 static gboolean
1091 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1092 {
1093         unsigned char b;
1094         const unsigned char *ptr = (const unsigned char *)_ptr;
1095
1096         if (!available)
1097                 return FALSE;
1098
1099         b = *ptr;
1100         *value = *size = 0;
1101         
1102         if ((b & 0x80) == 0) {
1103                 *size = 1;
1104                 *value = b;
1105         } else if ((b & 0x40) == 0) {
1106                 if (available < 2)
1107                         return FALSE;
1108                 *size = 2;
1109                 *value = ((b & 0x3f) << 8 | ptr [1]);
1110         } else {
1111                 if (available < 4)
1112                         return FALSE;
1113                 *size = 4;
1114                 *value  = ((b & 0x1f) << 24) |
1115                         (ptr [1] << 16) |
1116                         (ptr [2] << 8) |
1117                         ptr [3];
1118         }
1119
1120         return TRUE;
1121 }
1122
1123 static gboolean
1124 decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
1125 {
1126         MonoStreamHeader blob = ctx->image->heap_blob;
1127         guint32 value, enc_size;
1128
1129         if (offset >= blob.size)
1130                 return FALSE;
1131
1132         if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1133                 return FALSE;
1134
1135         if (offset + enc_size + value < offset)
1136                 return FALSE;
1137
1138         if (offset + enc_size + value > blob.size)
1139                 return FALSE;
1140
1141         *size = value;
1142         *first_byte = blob.data + offset + enc_size;
1143         return TRUE;
1144 }
1145
1146 static gboolean
1147 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1148 {
1149         const char *ptr = *_ptr;
1150         if (ptr + size > limit)
1151                 return FALSE;
1152         switch (size) {
1153         case 1:
1154                 *dest = *((guint8*)ptr);
1155                 ++ptr;
1156                 break;
1157         case 2:
1158                 *dest = read16 (ptr);
1159                 ptr += 2;
1160                 break;
1161         case 4:
1162                 *dest = read32 (ptr);
1163                 ptr += 4;
1164                 break;
1165         }
1166         *_ptr = ptr;
1167         return TRUE;
1168 }
1169
1170 static gboolean
1171 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1172 {
1173         unsigned size = 0;
1174         const char *ptr = *_ptr;
1175         gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1176         *_ptr = ptr + size;
1177         return res;
1178 }
1179
1180 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1181 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1182 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1183 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1184
1185 static gboolean
1186 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1187
1188 static gboolean
1189 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1190
1191 static gboolean
1192 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1193 {
1194         const char *ptr = *_ptr;
1195         unsigned type = 0;
1196         unsigned token = 0;
1197
1198         while (TRUE) {
1199                 if (!safe_read8 (type, ptr, end))
1200                         FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1201         
1202                 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1203                         --ptr;
1204                         break;
1205                 }
1206         
1207                 if (!safe_read_cint (token, ptr, end))
1208                         FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1209         
1210                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1211                         FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1212         }
1213
1214         *_ptr = ptr;
1215         return TRUE;
1216 }
1217
1218 static gboolean
1219 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1220 {
1221         const char *ptr = *_ptr;
1222         unsigned val = 0;
1223         unsigned size, num, i;
1224
1225         if (!safe_read8 (val, ptr, end))
1226                 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1227
1228         if (val == 0)
1229                 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1230
1231         if (!safe_read_cint (size, ptr, end))
1232                 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1233
1234         for (i = 0; i < size; ++i) {
1235                 if (!safe_read_cint (num, ptr, end))
1236                         FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1237         }
1238
1239         if (!safe_read_cint (size, ptr, end))
1240                 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1241
1242         for (i = 0; i < size; ++i) {
1243                 if (!safe_read_cint (num, ptr, end))
1244                         FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1245         }
1246
1247         *_ptr = ptr;
1248         return TRUE;
1249 }
1250
1251 static gboolean
1252 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1253 {
1254         const char *ptr = *_ptr;
1255         unsigned type;
1256         unsigned count, token, i;
1257
1258         if (!safe_read8 (type, ptr, end))
1259                 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1260
1261         if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1262                 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1263
1264         if (!safe_read_cint (token, ptr, end))
1265                 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1266
1267         if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1268                 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1269
1270         if (!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_blob (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_FINAL)
2256                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2257                         if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2258                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2259                 }
2260
2261                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2262                         ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2263
2264                 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2265                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2266
2267                 //XXX no checks against cas stuff 10,11,12,13)
2268
2269                 //TODO check iface with .ctor (15,16)
2270
2271                 if (i + 1 < module_method_list) {
2272                         if (!(flags & METHOD_ATTRIBUTE_STATIC))
2273                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2274                         if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2275                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2276                         if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2277                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2278                 }
2279
2280                 //TODO check valuetype for synchronized
2281
2282                 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2283                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2284
2285                 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2286                         if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2287                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2288                         if (!(flags & METHOD_ATTRIBUTE_STATIC))
2289                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2290                 }
2291
2292                 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && 
2293                                 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2294                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2295
2296                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2297                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2298
2299                 //TODO check signature contents
2300
2301                 if (rva) {
2302                         if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2303                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2304                         if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2305                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2306                 } else {
2307                         if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2308                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2309                 }
2310
2311                 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2312                         if (rva)
2313                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2314                         if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2315                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2316                 }
2317                 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2318                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2319
2320                 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2321                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2322
2323                 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2324                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2325
2326                 if (data [MONO_METHOD_PARAMLIST] == 0)
2327                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2328
2329                 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2330                         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));
2331
2332                 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2333                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2334
2335                 paramlist = data [MONO_METHOD_PARAMLIST];
2336
2337         }
2338 }
2339
2340 static void
2341 verify_method_table_full (VerifyContext *ctx)
2342 {
2343         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2344         guint32 data [MONO_METHOD_SIZE], rva;
2345         int i;
2346
2347         for (i = 0; i < table->rows; ++i) {
2348                 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2349                 rva = data [MONO_METHOD_RVA];
2350
2351                 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2352                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2353
2354                 if (rva && !is_valid_method_header (ctx, rva))
2355                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2356         }
2357 }
2358
2359 static guint32
2360 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2361 {
2362         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2363         guint32 row = *current_method;
2364         guint32 paramlist, tmp;
2365
2366
2367         paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2368         while (row < table->rows) {
2369                 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2370                 if (tmp > paramlist) {
2371                         *current_method = row;
2372                         return tmp - paramlist;
2373                 }
2374                 ++row;
2375         }
2376
2377         /*no more methods, all params apply to the last one*/
2378         *current_method = table->rows;
2379         return (guint32)-1;
2380 }
2381
2382
2383 #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))
2384 static void
2385 verify_param_table (VerifyContext *ctx)
2386 {
2387         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2388         guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2389         gboolean first_param = TRUE;
2390         int i;
2391
2392         if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2393                 if (table->rows > 0)
2394                         ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2395                 return;
2396         }
2397         
2398         remaining_params = get_next_param_count (ctx, &current_method);
2399
2400         for (i = 0; i < table->rows; ++i) {
2401                 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2402                 flags = data [MONO_PARAM_FLAGS];
2403
2404                 if (flags & INVALID_PARAM_FLAGS_BITS)
2405                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2406
2407                 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2408                         if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2409                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2410                 } else {
2411                         if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2412                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2413                 }
2414
2415                 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)
2416                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2417
2418                 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2419                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2420
2421                 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2422                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2423
2424                 first_param = FALSE;
2425                 sequence = data [MONO_PARAM_SEQUENCE];
2426                 if (--remaining_params == 0) {
2427                         remaining_params = get_next_param_count (ctx, &current_method);
2428                         first_param = TRUE;
2429                 }
2430         }
2431 }
2432
2433 static void
2434 verify_interfaceimpl_table (VerifyContext *ctx)
2435 {
2436         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2437         guint32 data [MONO_INTERFACEIMPL_SIZE];
2438         int i;
2439
2440         for (i = 0; i < table->rows; ++i) {
2441                 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2442                 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2443                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2444
2445                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2446                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2447
2448                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2449                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2450         }
2451 }
2452
2453 static void
2454 verify_memberref_table (VerifyContext *ctx)
2455 {
2456         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2457         guint32 data [MONO_MEMBERREF_SIZE];
2458         int i;
2459
2460         for (i = 0; i < table->rows; ++i) {
2461                 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2462
2463                 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2464                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2465
2466                 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2467                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2468
2469                 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2470                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2471
2472                 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2473                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2474         }
2475 }
2476
2477
2478 static void
2479 verify_memberref_table_full (VerifyContext *ctx)
2480 {
2481         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2482         guint32 data [MONO_MEMBERREF_SIZE];
2483         int i;
2484
2485         for (i = 0; i < table->rows; ++i) {
2486                 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2487
2488                 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2489                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field  0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2490         }
2491 }
2492
2493 static void
2494 verify_constant_table (VerifyContext *ctx)
2495 {
2496         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2497         guint32 data [MONO_CONSTANT_SIZE], type;
2498         int i;
2499
2500         for (i = 0; i < table->rows; ++i) {
2501                 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2502                 type = data [MONO_CONSTANT_TYPE];
2503
2504                 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2505                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2506
2507                 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2508                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2509
2510                 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2511                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2512
2513                 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2514                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2515         }
2516 }
2517
2518 static void
2519 verify_cattr_table (VerifyContext *ctx)
2520 {
2521         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2522         guint32 data [MONO_CUSTOM_ATTR_SIZE];
2523         int i;
2524
2525         for (i = 0; i < table->rows; ++i) {
2526                 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2527
2528                 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2529                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2530
2531                 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2532                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2533
2534                 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2535                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2536         }
2537 }
2538
2539 static void
2540 verify_cattr_table_full (VerifyContext *ctx)
2541 {
2542         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2543         guint32 data [MONO_CUSTOM_ATTR_SIZE];
2544         int i;
2545
2546         for (i = 0; i < table->rows; ++i) {
2547                 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2548
2549                 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2550                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2551         }
2552 }
2553
2554 static void
2555 verify_field_marshal_table (VerifyContext *ctx)
2556 {
2557         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2558         guint32 data [MONO_FIELD_MARSHAL_SIZE];
2559         int i;
2560
2561         for (i = 0; i < table->rows; ++i) {
2562                 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2563
2564                 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2565                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2566
2567                 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2568                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2569
2570                 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2571                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2572
2573                 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2574                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2575         }
2576 }
2577
2578 static void
2579 verify_field_marshal_table_full (VerifyContext *ctx)
2580 {
2581         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2582         guint32 data [MONO_FIELD_MARSHAL_SIZE];
2583         int i;
2584
2585         for (i = 0; i < table->rows; ++i) {
2586                 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2587
2588                 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2589                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2590         }
2591 }
2592
2593 static void
2594 verify_decl_security_table (VerifyContext *ctx)
2595 {
2596         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2597         guint32 data [MONO_DECL_SECURITY_SIZE];
2598         int i;
2599
2600         for (i = 0; i < table->rows; ++i) {
2601                 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2602
2603                 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2604                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2605
2606                 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2607                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2608
2609                 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2610                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2611         }
2612 }
2613
2614 static void
2615 verify_decl_security_table_full (VerifyContext *ctx)
2616 {
2617         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2618         guint32 data [MONO_DECL_SECURITY_SIZE];
2619         int i;
2620
2621         for (i = 0; i < table->rows; ++i) {
2622                 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2623
2624                 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2625                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2626         }
2627 }
2628
2629 static void
2630 verify_class_layout_table (VerifyContext *ctx)
2631 {
2632         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2633         guint32 data [MONO_CLASS_LAYOUT_SIZE];
2634         int i;
2635
2636         for (i = 0; i < table->rows; ++i) {
2637                 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2638
2639                 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2640                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2641
2642                 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2643                 case 0:
2644                 case 1:
2645                 case 2:
2646                 case 4:
2647                 case 8:
2648                 case 16:
2649                 case 32:
2650                 case 64:
2651                 case 128:
2652                         break;
2653                 default:
2654                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2655                 }
2656         }
2657 }
2658
2659 static void
2660 verify_field_layout_table (VerifyContext *ctx)
2661 {
2662         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2663         guint32 data [MONO_FIELD_LAYOUT_SIZE];
2664         int i;
2665
2666         for (i = 0; i < table->rows; ++i) {
2667                 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2668
2669                 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2670                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2671         }
2672 }
2673
2674 static void
2675 verify_standalonesig_table (VerifyContext *ctx)
2676 {
2677         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2678         guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2679         int i;
2680
2681         for (i = 0; i < table->rows; ++i) {
2682                 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2683
2684                 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
2685                         ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2686         }
2687 }
2688
2689 static void
2690 verify_standalonesig_table_full (VerifyContext *ctx)
2691 {
2692         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2693         guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2694         int i;
2695
2696         for (i = 0; i < table->rows; ++i) {
2697                 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2698
2699                 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2700                         ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2701         }
2702 }
2703
2704 static void
2705 verify_eventmap_table (VerifyContext *ctx)
2706 {
2707         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2708         guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2709         int i;
2710
2711         for (i = 0; i < table->rows; ++i) {
2712                 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2713
2714                 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2715                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2716
2717                 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2718                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2719
2720                 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2721         }
2722 }
2723
2724 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2725 static void
2726 verify_event_table (VerifyContext *ctx)
2727 {
2728         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2729         guint32 data [MONO_EVENT_SIZE];
2730         int i;
2731
2732         for (i = 0; i < table->rows; ++i) {
2733                 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2734
2735                 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2736                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2737
2738                 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2739                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2740
2741                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2742                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2743         }
2744 }
2745
2746 static void
2747 verify_event_table_full (VerifyContext *ctx)
2748 {
2749         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2750         MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2751         guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2752         gboolean found_add, found_remove;
2753         int i, idx;
2754
2755         for (i = 0; i < table->rows; ++i) {
2756                 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2757
2758                 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2759                 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2760                 if (idx == -1)
2761                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2762
2763                 //first we move to the first row for this event
2764                 while (idx > 0) {
2765                         if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2766                                 break;
2767                         --idx;
2768                 }
2769                 //now move forward looking for AddOn and RemoveOn rows
2770                 found_add = found_remove = FALSE;
2771                 while (idx < sema_table->rows) {
2772                         mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2773                         if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2774                                 break;
2775                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2776                                 found_add = TRUE;
2777                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2778                                 found_remove = TRUE;
2779                         if (found_add && found_remove)
2780                                 break;
2781                         ++idx;
2782                 }
2783
2784                 if (!found_add)
2785                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2786                 if (!found_remove)
2787                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2788         }
2789 }
2790
2791 static void
2792 verify_propertymap_table (VerifyContext *ctx)
2793 {
2794         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2795         guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2796         int i;
2797
2798         for (i = 0; i < table->rows; ++i) {
2799                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2800
2801                 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2802                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2803
2804                 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2805                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2806
2807                 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2808         }
2809 }
2810
2811 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2812 static void
2813 verify_property_table (VerifyContext *ctx)
2814 {
2815         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2816         guint32 data [MONO_PROPERTY_SIZE];
2817         int i;
2818
2819         for (i = 0; i < table->rows; ++i) {
2820                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2821
2822                 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2823                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2824
2825                 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2826                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2827
2828                 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2829                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2830
2831                 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2832                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2833                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2834
2835         }
2836 }
2837
2838 static void
2839 verify_methodimpl_table (VerifyContext *ctx)
2840 {
2841         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2842         guint32 data [MONO_METHODIMPL_SIZE];
2843         int i;
2844
2845         for (i = 0; i < table->rows; ++i) {
2846                 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2847
2848                 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2849                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2850                         
2851                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2852                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2853                 
2854                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2855                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2856
2857                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2858                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2859                 
2860                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2861                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2862         }
2863 }
2864
2865 static void
2866 verify_moduleref_table (VerifyContext *ctx)
2867 {
2868         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2869         guint32 data [MONO_MODULEREF_SIZE];
2870         int i;
2871
2872         for (i = 0; i < table->rows; ++i) {
2873                 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2874
2875                 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2876                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2877         }
2878 }
2879
2880 static void
2881 verify_typespec_table (VerifyContext *ctx)
2882 {
2883         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2884         guint32 data [MONO_TYPESPEC_SIZE];
2885         int i;
2886
2887         for (i = 0; i < table->rows; ++i) {
2888                 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2889
2890                 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
2891                         ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2892         }
2893 }
2894
2895 static void
2896 verify_typespec_table_full (VerifyContext *ctx)
2897 {
2898         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2899         guint32 data [MONO_TYPESPEC_SIZE];
2900         int i;
2901
2902         for (i = 0; i < table->rows; ++i) {
2903                 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2904
2905                 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2906                         ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2907         }
2908 }
2909
2910 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
2911 static void
2912 verify_implmap_table (VerifyContext *ctx)
2913 {
2914         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2915         guint32 data [MONO_IMPLMAP_SIZE], cconv;
2916         int i;
2917
2918         for (i = 0; i < table->rows; ++i) {
2919                 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2920
2921                 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2922                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2923
2924                 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2925                 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2926                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2927
2928                 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2929                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2930
2931                 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2932                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2933
2934                 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2935                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2936
2937                 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2938                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2939
2940                 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
2941                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2942         }
2943 }
2944
2945 static void
2946 verify_fieldrva_table (VerifyContext *ctx)
2947 {
2948         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2949         guint32 data [MONO_FIELD_RVA_SIZE];
2950         int i;
2951
2952         for (i = 0; i < table->rows; ++i) {
2953                 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2954
2955                 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2956                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2957
2958                 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2959                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2960         }
2961 }
2962
2963 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
2964 static void
2965 verify_assembly_table (VerifyContext *ctx)
2966 {
2967         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2968         guint32 data [MONO_ASSEMBLY_SIZE], hash;
2969         int i;
2970
2971         if (table->rows > 1)
2972                 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2973
2974         for (i = 0; i < table->rows; ++i) {
2975                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2976
2977                 hash = data [MONO_ASSEMBLY_HASH_ALG];
2978                 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2979                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2980
2981                 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2982                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2983
2984                 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
2985                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2986
2987                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2988                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2989
2990                 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2991                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2992         }
2993 }
2994
2995 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2996 static void
2997 verify_assemblyref_table (VerifyContext *ctx)
2998 {
2999         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3000         guint32 data [MONO_ASSEMBLYREF_SIZE];
3001         int i;
3002
3003         for (i = 0; i < table->rows; ++i) {
3004                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3005
3006                 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3007                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3008
3009                 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3010                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3011
3012                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3013                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3014
3015                 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3016                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3017
3018                 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3019                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3020         }
3021 }
3022
3023 #define INVALID_FILE_FLAGS_BITS ~(1)
3024 static void
3025 verify_file_table (VerifyContext *ctx)
3026 {
3027         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3028         guint32 data [MONO_FILE_SIZE];
3029         int i;
3030
3031         for (i = 0; i < table->rows; ++i) {
3032                 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3033                 
3034                 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3035                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3036
3037                 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3038                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3039
3040                 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3041                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3042         }
3043 }
3044
3045 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3046 static void
3047 verify_exportedtype_table (VerifyContext *ctx)
3048 {
3049         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3050         guint32 data [MONO_EXP_TYPE_SIZE];
3051         int i;
3052
3053         for (i = 0; i < table->rows; ++i) {
3054                 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3055                 
3056                 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3057                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3058
3059                 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3060                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3061
3062                 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3063                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3064
3065                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3066                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3067
3068                 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3069                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3070
3071                 /*nested type can't have a namespace*/
3072                 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3073                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3074         }
3075 }
3076
3077 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3078 static void
3079 verify_manifest_resource_table (VerifyContext *ctx)
3080 {
3081         MonoCLIImageInfo *iinfo = ctx->image->image_info;
3082         MonoCLIHeader *ch = &iinfo->cli_cli_header;
3083         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3084         guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3085         int i;
3086
3087         resources_size = ch->ch_resources.size;
3088
3089         for (i = 0; i < table->rows; ++i) {
3090                 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3091
3092                 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3093                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3094
3095                 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3096                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3097
3098                 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3099                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3100
3101                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3102                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3103
3104                 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3105                 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3106
3107                 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3108                         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])));
3109
3110                 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3111                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3112
3113                 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3114                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3115         }
3116 }
3117
3118 static void
3119 verify_nested_class_table (VerifyContext *ctx)
3120 {
3121         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3122         guint32 data [MONO_NESTED_CLASS_SIZE];
3123         int i;
3124
3125         for (i = 0; i < table->rows; ++i) {
3126                 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3127
3128                 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3129                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3130                 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3131                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3132                 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3133                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass  and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3134         }
3135 }
3136
3137 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3138 static void
3139 verify_generic_param_table (VerifyContext *ctx)
3140 {
3141         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3142         guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3143         int i, param_number = 0;
3144
3145         for (i = 0; i < table->rows; ++i) {
3146                 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3147
3148                 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3149                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3150
3151                 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3152                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3153
3154                 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3155                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3156
3157                 token = data [MONO_GENERICPARAM_OWNER];
3158
3159                 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3160                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3161
3162                 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3163                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3164
3165                 if (token != last_token) {
3166                         param_number = 0;
3167                         last_token = token;
3168                 }
3169
3170                 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3171                         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));
3172
3173                 ++param_number;
3174         }
3175 }
3176
3177 static void
3178 verify_method_spec_table (VerifyContext *ctx)
3179 {
3180         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3181         guint32 data [MONO_METHODSPEC_SIZE];
3182         int i;
3183
3184         for (i = 0; i < table->rows; ++i) {
3185                 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3186
3187                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3188                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3189
3190                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3191                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3192
3193                 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3194                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3195         }
3196 }
3197
3198 static void
3199 verify_method_spec_table_full (VerifyContext *ctx)
3200 {
3201         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3202         guint32 data [MONO_METHODSPEC_SIZE];
3203         int i;
3204
3205         for (i = 0; i < table->rows; ++i) {
3206                 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3207
3208                 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3209                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3210         }
3211 }
3212
3213 static void
3214 verify_generic_param_constraint_table (VerifyContext *ctx)
3215 {
3216         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3217         guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3218         int i;
3219
3220         for (i = 0; i < table->rows; ++i) {
3221                 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3222
3223                 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3224                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3225
3226                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3227                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3228
3229                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3230                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3231         }
3232 }
3233
3234
3235 typedef struct {
3236         const char *name;
3237         const char *name_space;
3238         guint32 resolution_scope;
3239 } TypeDefUniqueId;
3240
3241 static guint
3242 typedef_hash (gconstpointer _key)
3243 {
3244         const TypeDefUniqueId *key = _key;
3245         return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3246 }
3247
3248 static gboolean
3249 typedef_equals (gconstpointer _a, gconstpointer _b)
3250 {
3251         const TypeDefUniqueId *a = _a;
3252         const TypeDefUniqueId *b = _b;
3253         return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3254 }
3255
3256 static void
3257 verify_typedef_table_global_constraints (VerifyContext *ctx)
3258 {
3259         int i;
3260         guint32 data [MONO_TYPEDEF_SIZE];
3261         guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3262         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3263         MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3264         GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3265
3266         for (i = 0; i < table->rows; ++i) {
3267                 guint visibility;
3268                 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3269                 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3270
3271                 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3272                 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3273                 type->resolution_scope = 0;
3274
3275                 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3276                 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3277                         int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3278                         g_assert (res >= 0);
3279
3280                         mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3281                         type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3282                 }
3283
3284                 if (g_hash_table_lookup (unique_types, type)) {
3285                         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));
3286                         g_hash_table_destroy (unique_types);
3287                         g_free (type);
3288                         return;
3289                 }
3290                 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3291         }
3292
3293         g_hash_table_destroy (unique_types);
3294 }
3295
3296 static void
3297 verify_typeref_table_global_constraints (VerifyContext *ctx)
3298 {
3299         int i;
3300         guint32 data [MONO_TYPEREF_SIZE];
3301         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3302         GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3303
3304         for (i = 0; i < table->rows; ++i) {
3305                 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3306                 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3307
3308                 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3309                 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3310                 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3311
3312                 if (g_hash_table_lookup (unique_types, type)) {
3313                         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));
3314                         g_hash_table_destroy (unique_types);
3315                         g_free (type);
3316                         return;
3317                 }
3318                 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3319         }
3320
3321         g_hash_table_destroy (unique_types);
3322 }
3323
3324 static void
3325 verify_tables_data_global_constraints (VerifyContext *ctx)
3326 {
3327         verify_typeref_table_global_constraints (ctx);
3328         CHECK_ERROR ();
3329         verify_typedef_table_global_constraints (ctx);
3330 }
3331         
3332 static void
3333 verify_tables_data (VerifyContext *ctx)
3334 {
3335         OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3336         guint32 size = 0, tables_offset;
3337         int i;
3338
3339         for (i = 0; i < 0x2D; ++i) {
3340                 MonoTableInfo *table = &ctx->image->tables [i];
3341                 guint32 tmp_size;
3342                 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3343                 if (tmp_size < size) {
3344                         size = 0;
3345                         break;
3346                 }
3347                 size = tmp_size;                        
3348         }
3349
3350         if (size == 0)
3351                 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3352
3353         tables_offset = ctx->image->tables_base - ctx->data;
3354         if (!bounds_check_offset (&tables_area, tables_offset, size))
3355                 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)));
3356
3357         verify_module_table (ctx);
3358         CHECK_ERROR ();
3359         verify_typeref_table (ctx);
3360         CHECK_ERROR ();
3361         verify_typedef_table (ctx);
3362         CHECK_ERROR ();
3363         verify_field_table (ctx);
3364         CHECK_ERROR ();
3365         verify_method_table (ctx);
3366         CHECK_ERROR ();
3367         verify_param_table (ctx);
3368         CHECK_ERROR ();
3369         verify_interfaceimpl_table (ctx);
3370         CHECK_ERROR ();
3371         verify_memberref_table (ctx);
3372         CHECK_ERROR ();
3373         verify_constant_table (ctx);
3374         CHECK_ERROR ();
3375         verify_cattr_table (ctx);
3376         CHECK_ERROR ();
3377         verify_field_marshal_table (ctx);
3378         CHECK_ERROR ();
3379         verify_decl_security_table (ctx);
3380         CHECK_ERROR ();
3381         verify_class_layout_table (ctx);
3382         CHECK_ERROR ();
3383         verify_field_layout_table (ctx);
3384         CHECK_ERROR ();
3385         verify_standalonesig_table (ctx);
3386         CHECK_ERROR ();
3387         verify_eventmap_table (ctx);
3388         CHECK_ERROR ();
3389         verify_event_table (ctx);
3390         CHECK_ERROR ();
3391         verify_propertymap_table (ctx);
3392         CHECK_ERROR ();
3393         verify_property_table (ctx);
3394         CHECK_ERROR ();
3395         verify_methodimpl_table (ctx);
3396         CHECK_ERROR ();
3397         verify_moduleref_table (ctx);
3398         CHECK_ERROR ();
3399         verify_typespec_table (ctx);
3400         CHECK_ERROR ();
3401         verify_implmap_table (ctx);
3402         CHECK_ERROR ();
3403         verify_fieldrva_table (ctx);
3404         CHECK_ERROR ();
3405         verify_assembly_table (ctx);
3406         CHECK_ERROR ();
3407         verify_assemblyref_table (ctx);
3408         CHECK_ERROR ();
3409         verify_file_table (ctx);
3410         CHECK_ERROR ();
3411         verify_exportedtype_table (ctx);
3412         CHECK_ERROR ();
3413         verify_manifest_resource_table (ctx);
3414         CHECK_ERROR ();
3415         verify_nested_class_table (ctx);
3416         CHECK_ERROR ();
3417         verify_generic_param_table (ctx);
3418         CHECK_ERROR ();
3419         verify_method_spec_table (ctx);
3420         CHECK_ERROR ();
3421         verify_generic_param_constraint_table (ctx);
3422         CHECK_ERROR ();
3423         verify_tables_data_global_constraints (ctx);
3424 }
3425
3426 static void
3427 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
3428 {
3429         memset (ctx, 0, sizeof (VerifyContext));
3430         ctx->image = image;
3431         ctx->report_error = error_list != NULL;
3432         ctx->report_warning = FALSE; //export this setting in the API
3433         ctx->valid = 1;
3434         ctx->size = image->raw_data_len;
3435         ctx->data = image->raw_data;
3436 }
3437
3438 static gboolean
3439 cleanup_context (VerifyContext *ctx, GSList **error_list)
3440 {
3441         g_free (ctx->sections);
3442         if (error_list)
3443                 *error_list = ctx->errors;
3444         else
3445                 mono_free_verify_list (ctx->errors);
3446         return ctx->valid;      
3447 }
3448
3449 gboolean
3450 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3451 {
3452         VerifyContext ctx;
3453
3454         if (!mono_verifier_is_enabled_for_image (image))
3455                 return TRUE;
3456
3457         init_verify_context (&ctx, image, error_list);
3458         ctx.stage = STAGE_PE;
3459
3460         verify_msdos_header (&ctx);
3461         CHECK_STATE();
3462         verify_pe_header (&ctx);
3463         CHECK_STATE();
3464         verify_pe_optional_header (&ctx);
3465         CHECK_STATE();
3466         load_section_table (&ctx);
3467         CHECK_STATE();
3468         load_data_directories (&ctx);
3469         CHECK_STATE();
3470         verify_import_table (&ctx);
3471         CHECK_STATE();
3472         /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3473         verify_resources_table (&ctx);
3474
3475 cleanup:
3476         return cleanup_context (&ctx, error_list);
3477 }
3478
3479 gboolean
3480 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3481 {
3482         VerifyContext ctx;
3483
3484         if (!mono_verifier_is_enabled_for_image (image))
3485                 return TRUE;
3486
3487         init_verify_context (&ctx, image, error_list);
3488         ctx.stage = STAGE_CLI;
3489
3490         verify_cli_header (&ctx);
3491         CHECK_STATE();
3492         verify_metadata_header (&ctx);
3493         CHECK_STATE();
3494         verify_tables_schema (&ctx);
3495
3496 cleanup:
3497         return cleanup_context (&ctx, error_list);
3498 }
3499
3500
3501 /*
3502  * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3503  * Other verification checks are meant to be done lazily by the runtime. Those include:
3504  *      blob items (signatures, method headers, custom attributes, etc)
3505  *  type semantics related
3506  *  vtable related
3507  *  stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3508  * 
3509  * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3510  * operation still need more checking.
3511  */
3512 gboolean
3513 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3514 {
3515         VerifyContext ctx;
3516
3517         if (!mono_verifier_is_enabled_for_image (image))
3518                 return TRUE;
3519
3520         init_verify_context (&ctx, image, error_list);
3521         ctx.stage = STAGE_TABLES;
3522
3523         verify_tables_data (&ctx);
3524
3525         return cleanup_context (&ctx, error_list);
3526 }
3527
3528
3529 /*
3530  * Verifies all other constraints.
3531  */
3532 gboolean
3533 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3534 {
3535         VerifyContext ctx;
3536
3537         if (!mono_verifier_is_enabled_for_image (image))
3538                 return TRUE;
3539
3540         init_verify_context (&ctx, image, error_list);
3541         ctx.stage = STAGE_TABLES;
3542
3543         verify_typedef_table_full (&ctx);
3544         CHECK_STATE ();
3545         verify_field_table_full (&ctx);
3546         CHECK_STATE ();
3547         verify_method_table_full (&ctx);
3548         CHECK_STATE ();
3549         verify_memberref_table_full (&ctx);
3550         CHECK_STATE ();
3551         verify_cattr_table_full (&ctx);
3552         CHECK_STATE ();
3553         verify_field_marshal_table_full (&ctx);
3554         CHECK_STATE ();
3555         verify_decl_security_table_full (&ctx);
3556         CHECK_STATE ();
3557         verify_standalonesig_table_full (&ctx);
3558         CHECK_STATE ();
3559         verify_event_table_full (&ctx);
3560         CHECK_STATE ();
3561         verify_typespec_table_full (&ctx);
3562         CHECK_STATE ();
3563         verify_method_spec_table_full (&ctx);
3564
3565 cleanup:
3566         return cleanup_context (&ctx, error_list);
3567 }
3568
3569 gboolean
3570 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3571 {
3572         VerifyContext ctx;
3573
3574         if (!mono_verifier_is_enabled_for_image (image))
3575                 return TRUE;
3576
3577         init_verify_context (&ctx, image, error_list);
3578         ctx.stage = STAGE_TABLES;
3579
3580         is_valid_field_signature (&ctx, offset);
3581         return cleanup_context (&ctx, error_list);
3582 }
3583
3584 gboolean
3585 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3586 {
3587         VerifyContext ctx;
3588
3589         if (!mono_verifier_is_enabled_for_image (image))
3590                 return TRUE;
3591
3592         init_verify_context (&ctx, image, error_list);
3593         ctx.stage = STAGE_TABLES;
3594
3595         is_valid_method_header (&ctx, offset);
3596         return cleanup_context (&ctx, error_list);
3597 }
3598
3599 gboolean
3600 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3601 {
3602         VerifyContext ctx;
3603
3604         if (!mono_verifier_is_enabled_for_image (image))
3605                 return TRUE;
3606
3607         init_verify_context (&ctx, image, error_list);
3608         ctx.stage = STAGE_TABLES;
3609
3610         is_valid_method_signature (&ctx, offset);
3611         return cleanup_context (&ctx, error_list);
3612 }
3613
3614 gboolean
3615 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3616 {
3617         VerifyContext ctx;
3618
3619         if (!mono_verifier_is_enabled_for_image (image))
3620                 return TRUE;
3621
3622         init_verify_context (&ctx, image, error_list);
3623         ctx.stage = STAGE_TABLES;
3624
3625         is_valid_method_or_field_signature (&ctx, offset);
3626         return cleanup_context (&ctx, error_list);
3627 }
3628
3629 gboolean
3630 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3631 {
3632         VerifyContext ctx;
3633
3634         if (!mono_verifier_is_enabled_for_image (image))
3635                 return TRUE;
3636
3637         init_verify_context (&ctx, image, error_list);
3638         ctx.stage = STAGE_TABLES;
3639
3640         is_valid_standalonesig_blob (&ctx, offset);
3641         return cleanup_context (&ctx, error_list);
3642 }
3643
3644 gboolean
3645 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3646 {
3647         VerifyContext ctx;
3648
3649         if (!mono_verifier_is_enabled_for_image (image))
3650                 return TRUE;
3651
3652         init_verify_context (&ctx, image, error_list);
3653         ctx.stage = STAGE_TABLES;
3654
3655         is_valid_typespec_blob (&ctx, offset);
3656         return cleanup_context (&ctx, error_list);
3657 }
3658
3659 gboolean
3660 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3661 {
3662         VerifyContext ctx;
3663
3664         if (!mono_verifier_is_enabled_for_image (image))
3665                 return TRUE;
3666
3667         init_verify_context (&ctx, image, error_list);
3668         ctx.stage = STAGE_TABLES;
3669
3670         is_valid_methodspec_blob (&ctx, offset);
3671         return cleanup_context (&ctx, error_list);
3672 }
3673
3674 static void
3675 verify_user_string (VerifyContext *ctx, guint32 offset)
3676 {
3677         OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
3678         guint32 entry_size, bytes;
3679
3680         if (heap_us.size < offset)
3681                 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
3682
3683         if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
3684                 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
3685
3686         if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
3687                 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
3688
3689         entry_size += bytes;
3690
3691         if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
3692                 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
3693 }
3694
3695 gboolean
3696 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
3697 {
3698         VerifyContext ctx;
3699
3700         if (!mono_verifier_is_enabled_for_image (image))
3701                 return TRUE;
3702
3703         init_verify_context (&ctx, image, error_list);
3704         ctx.stage = STAGE_TABLES;
3705
3706         verify_user_string (&ctx, offset);
3707
3708         return cleanup_context (&ctx, error_list);
3709 }
3710
3711
3712 #else
3713 gboolean
3714 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3715 {
3716         return TRUE;
3717 }
3718
3719 gboolean
3720 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3721 {
3722         return TRUE;
3723 }
3724
3725 gboolean
3726 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3727 {
3728         return TRUE;
3729 }
3730
3731 gboolean
3732 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3733 {
3734         return TRUE;
3735 }
3736
3737 gboolean
3738 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3739 {
3740         return TRUE;
3741 }
3742
3743 gboolean
3744 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3745 {
3746         return TRUE;
3747 }
3748
3749 gboolean
3750 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3751 {
3752         return TRUE;
3753 }
3754
3755 gboolean
3756 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3757 {
3758         return TRUE;
3759 }
3760
3761 gboolean
3762 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3763 {
3764         return TRUE;
3765 }
3766
3767 gboolean
3768 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3769 {
3770         return TRUE;
3771 }
3772
3773 gboolean
3774 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3775 {
3776         return TRUE;
3777 }
3778
3779 gboolean
3780 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
3781 {
3782         return TRUE;
3783 }
3784
3785
3786 #endif /* DISABLE_VERIFIER */