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