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