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