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