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