2009-04-16 Rodrigo Kumpera <rkumpera@novell.com>
[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
10 #include <mono/metadata/object-internals.h>
11 #include <mono/metadata/verify.h>
12 #include <mono/metadata/verify-internals.h>
13 #include <mono/metadata/opcodes.h>
14 #include <mono/metadata/tabledefs.h>
15 #include <mono/metadata/reflection.h>
16 #include <mono/metadata/debug-helpers.h>
17 #include <mono/metadata/mono-endian.h>
18 #include <mono/metadata/metadata.h>
19 #include <mono/metadata/metadata-internals.h>
20 #include <mono/metadata/class-internals.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/utils/strenc.h>
23 #include <string.h>
24 #include <signal.h>
25 #include <ctype.h>
26
27 /*
28  TODO add fail fast mode
29  TODO add PE32+ support
30  TODO verify the entry point RVA and content.
31  TODO load_section_table and load_data_directories must take PE32+ into account
32  TODO add section relocation support
33  TODO verify the relocation table, since we really don't use, no need so far.
34  TODO do full PECOFF resources verification 
35  TODO verify in the CLI header entry point and resources
36  TODO implement null token typeref validation  
37  TODO verify table wide invariants for typedef (sorting and uniqueness)
38  FIXME has_cattr coded index / 8 -> Permission table? -- it's decl security
39  FIXME use subtraction based bounds checking to avoid overflows
40  FIXME calc col size using coded_index_desc;
41 */
42
43 #ifdef MONO_VERIFIER_DEBUG
44 #define VERIFIER_DEBUG(code) do { code; } while (0)
45 #else
46 #define VERIFIER_DEBUG(code)
47 #endif
48
49 #define INVALID_OFFSET ((guint32)-1)
50
51 enum {
52         IMPORT_TABLE_IDX = 1, 
53         RESOURCE_TABLE_IDX = 2,
54         RELOCATION_TABLE_IDX = 5,
55         IAT_IDX = 12,
56         CLI_HEADER_IDX = 14,
57 };
58
59 enum {
60         STRINGS_STREAM,
61         USER_STRINGS_STREAM,
62         BLOB_STREAM,
63         GUID_STREAM,
64         TILDE_STREAM
65 };
66
67 enum {
68         COL_UINT8,
69         COL_UINT16,
70         COL_UINT32,
71
72         COL_STRING,
73         COL_GUID,
74         COL_BLOB,
75
76         COL_TYPE_DEF_OR_REF, /*includes typespec*/
77         COL_HAS_CONSTANT,
78         COL_HAS_CATTR,
79         COL_HAS_FIELD_MARSHAL,
80         COL_HAS_DECL_SECURITY,
81         COL_MEMBER_REF_PARENT,
82         COL_HAS_SEMANTICS,
83         COL_METHOD_DEF_OR_REF,
84         COL_MEMBER_FORWARDED,
85         COL_IMPLEMENTATION,
86         COL_CATTR_TYPE,
87         COL_RES_SCOPE,
88         COL_TYPE_OR_METHOD_DEF,
89
90         COL_TYPE_DEF,
91         COL_METHOD_DEF,
92         COL_FIELD,
93         COL_PARAM,
94         COL_PROPERTY,
95         COL_EVENT,
96         COL_GENERIC_PARAM,
97         COL_ASSEMBLY_REF,
98         COL_MODULE_REF,
99
100         COL_LAST
101 };
102
103 const static unsigned char table_desc [] = {
104         /* 0x00 Module */
105 #define MODULE_TABLE_DESC (0)
106         COL_UINT16, /*Generation*/
107         COL_STRING, /*Name*/
108         COL_GUID, /*Mvid*/
109         COL_GUID, /*EncId*/
110         COL_GUID, /*EncBaseId*/
111         COL_LAST,
112
113 #define TYPEREF_TABLE_DESC (MODULE_TABLE_DESC + 6)
114         /* 0x01 TypeRef */
115         COL_RES_SCOPE, /*ResolutionScope*/
116         COL_STRING, /*TypeName*/
117         COL_STRING, /*TypeNameSpace*/
118         COL_LAST,
119
120 #define TYPEDEF_TABLE_DESC (TYPEREF_TABLE_DESC + 4)
121         /* 0x02 TypeDef */
122         COL_UINT32, /*Flags*/
123         COL_STRING, /*TypeName*/
124         COL_STRING, /*TypeNameSpace*/
125         COL_TYPE_DEF_OR_REF, /*Extends*/
126         COL_FIELD, /*FieldList*/
127         COL_METHOD_DEF, /*FieldList*/
128         COL_LAST,
129
130 #define TABLE_03_DESC (TYPEDEF_TABLE_DESC + 7)
131         /* 0x03 non documented extension */
132         COL_LAST,
133
134 #define FIELD_TABLE_DESC (TABLE_03_DESC + 1)
135         /* 0x04 Field */
136         COL_UINT16, /*FieldAttributes*/
137         COL_STRING, /*Name*/
138         COL_BLOB, /*Signature*/
139         COL_LAST,
140
141 #define TABLE_05_DESC (FIELD_TABLE_DESC + 4)
142         /* 0x05 non documented extension */
143         COL_LAST,
144
145 #define METHODDEF_TABLE_DESC (TABLE_05_DESC + 1)
146         /* 0x06 MethodDef */
147         COL_UINT32, /*RVA*/
148         COL_UINT16, /*ImplFlags*/
149         COL_UINT16, /*Flags*/
150         COL_STRING, /*Name*/
151         COL_BLOB, /*Signature*/
152         COL_PARAM, /*ParamList*/
153         COL_LAST,
154
155 #define TABLE_07_DESC (METHODDEF_TABLE_DESC + 7)
156         /* 0x07 non documented extension */
157         COL_LAST,
158
159 #define PARAM_TABLE_DESC (TABLE_07_DESC + 1)
160         /* 0x08 Param */
161         COL_UINT16, /*Flags*/
162         COL_UINT16, /*Sequence*/
163         COL_STRING, /*Name*/
164         COL_LAST,
165
166 #define INTERFACE_IMPL_TABLE_DESC (PARAM_TABLE_DESC + 4)
167         /* 0x09 InterfaceImpl */
168         COL_TYPE_DEF, /*Class*/
169         COL_TYPE_DEF_OR_REF, /*Interface*/
170         COL_LAST,
171         
172 #define MEMBERREF_TABLE_DESC (INTERFACE_IMPL_TABLE_DESC + 3)
173         /* 0x0A MemberRef */
174         COL_MEMBER_REF_PARENT, /*Class*/
175         COL_STRING, /*Name*/
176         COL_BLOB, /*Signature*/
177         COL_LAST,
178
179 #define CONSTANT_TABLE_DESC (MEMBERREF_TABLE_DESC + 4)
180         /* 0x0B Constant */
181         COL_UINT8, /*Type*/
182         COL_UINT8, /*Padding*/
183         COL_HAS_CONSTANT, /*Parent*/
184         COL_BLOB, /*Value*/
185         COL_LAST,
186
187 #define CUSTOM_ATTRIBUTE_TABLE_DESC (CONSTANT_TABLE_DESC + 5)
188         /* 0x0C CustomAttribute */
189         COL_HAS_CATTR, /*Parent*/
190         COL_CATTR_TYPE, /*Type*/
191         COL_BLOB, /*Value*/
192         COL_LAST,
193
194 #define FIELD_MARSHAL_TABLE_DESC (CUSTOM_ATTRIBUTE_TABLE_DESC + 4)
195         /* 0x0D FieldMarshal */
196         COL_HAS_FIELD_MARSHAL, /*Parent*/
197         COL_BLOB, /*NativeType*/
198         COL_LAST,
199
200 #define DECL_SECURITY_TABLE_DESC (FIELD_MARSHAL_TABLE_DESC + 3)
201         /* 0x0E DeclSecurity */
202         COL_UINT16, /*Action*/
203         COL_HAS_DECL_SECURITY, /*Parent*/ 
204         COL_BLOB, /*PermissionSet*/
205         COL_LAST,
206
207 #define CLASS_LAYOUT_TABLE_DESC (DECL_SECURITY_TABLE_DESC + 4)
208         /* 0x0F ClassLayout */
209         COL_UINT16, /*Packingsize*/
210         COL_UINT32, /*ClassSize*/
211         COL_TYPE_DEF, /*Parent*/
212         COL_LAST,
213
214 #define FIELD_LAYOUT_TABLE_DESC (CLASS_LAYOUT_TABLE_DESC + 4)
215         /* 0x10 FieldLayout */
216         COL_UINT32, /*Offset*/
217         COL_FIELD, /*Field*/
218         COL_LAST,
219
220 #define STANDARD_ALONE_SIG_TABLE_DESC (FIELD_LAYOUT_TABLE_DESC + 3)
221         /* 0x11 StandAloneSig */
222         COL_BLOB, /*Signature*/
223         COL_LAST,
224
225 #define EVENT_MAP_TABLE_DESC (STANDARD_ALONE_SIG_TABLE_DESC + 2)
226         /* 0x12 EventMap */
227         COL_TYPE_DEF, /*Parent*/
228         COL_EVENT, /*EventList*/
229         COL_LAST,
230
231 #define TABLE_13_DESC (EVENT_MAP_TABLE_DESC + 3)
232         /* 0x13 non documented extension */
233         COL_LAST,
234
235 #define EVENT_TABLE_DESC (TABLE_13_DESC + 1)
236         /* 0x14 Event */
237         COL_UINT16, /*EventFlags*/
238         COL_STRING, /*Name*/
239         COL_TYPE_DEF_OR_REF, /*EventType*/
240         COL_LAST,
241
242 #define PROPERTY_MAP_TABLE_DESC (EVENT_TABLE_DESC + 4)
243         /* 0x15 PropertyMap */
244         COL_TYPE_DEF, /*Parent*/
245         COL_PROPERTY, /*PropertyList*/
246         COL_LAST,
247
248 #define TABLE_16_DESC (PROPERTY_MAP_TABLE_DESC + 3)
249         /* 0x16 non documented extension */
250         COL_LAST,
251
252 #define PROPERTY_TABLE_DESC (TABLE_16_DESC + 1)
253         /* 0x17 Property */
254         COL_UINT16, /*Flags*/
255         COL_STRING, /*Name*/
256         COL_BLOB, /*Signature*/
257         COL_LAST,
258
259 #define METHOD_SEMANTICS_TABLE_DESC (PROPERTY_TABLE_DESC + 4)
260         /* 0x18 MethodSemantics */
261         COL_UINT16, /*Semantics*/
262         COL_METHOD_DEF, /*Method*/
263         COL_HAS_SEMANTICS, /*Association*/
264         COL_LAST,
265
266 #define METHOD_IMPL_TABLE_DESC (METHOD_SEMANTICS_TABLE_DESC + 4)
267         /* 0x19 MethodImpl */
268         COL_TYPE_DEF, /*Class*/
269         COL_METHOD_DEF_OR_REF, /*MethodBody*/
270         COL_METHOD_DEF_OR_REF, /*MethodDeclaration*/
271         COL_LAST,
272
273 #define MODULE_REF_TABLE_DESC (METHOD_IMPL_TABLE_DESC + 4)
274         /* 0x1A ModuleRef */
275         COL_STRING, /*Name*/
276         COL_LAST,
277
278 #define TYPESPEC_TABLE_DESC (MODULE_REF_TABLE_DESC + 2)
279         /* 0x1B TypeSpec */
280         COL_BLOB, /*Signature*/
281         COL_LAST,
282
283 #define IMPL_MAP_TABLE_DESC (TYPESPEC_TABLE_DESC + 2)
284         /* 0x1C ImplMap */
285         COL_UINT16, /*MappingFlags*/
286         COL_MEMBER_FORWARDED, /*MappingFlags*/
287         COL_STRING, /*ImportName*/
288         COL_MODULE_REF, /*ImportScope*/
289         COL_LAST,
290
291 #define FIELD_RVA_TABLE_DESC (IMPL_MAP_TABLE_DESC + 5)
292         /* 0x1D FieldRVA */
293         COL_UINT32, /*RVA*/
294         COL_FIELD, /*Field*/
295         COL_LAST,
296
297 #define TABLE_1E_DESC (IMPL_MAP_TABLE_DESC + 3)
298         /* 0x1E Unused */
299         COL_LAST,
300
301 #define TABLE_1F_DESC (TABLE_1E_DESC + 1)
302         /* 0x1F Unused */
303         COL_LAST,
304
305 #define ASSEMBLY_TABLE_DESC (TABLE_1F_DESC + 1)
306         /* 0x20 Assembly */
307         COL_UINT32, /*HashAlgId*/
308         COL_UINT16, /*Major*/
309         COL_UINT16, /*Minor*/
310         COL_UINT16, /*Build*/
311         COL_UINT16, /*Revision*/
312         COL_UINT32, /*Flags*/
313         COL_BLOB, /*PublicKey*/
314         COL_STRING, /*Name*/
315         COL_STRING, /*Culture*/
316         COL_LAST,
317
318 #define ASSEMBLY_PROCESSOR_TABLE_DESC (ASSEMBLY_TABLE_DESC + 10)
319         /* 0x21 AssemblyProcessor */
320         COL_UINT32, /*Processor*/
321         COL_LAST,
322
323 #define ASSEMBLY_OS_TABLE_DESC (ASSEMBLY_PROCESSOR_TABLE_DESC + 2)
324         /* 0x22 AssemblyOS */
325         COL_UINT32, /*OSPlatformID*/
326         COL_UINT32, /*OSMajorVersion*/
327         COL_UINT32, /*OSMinorVersion*/
328         COL_LAST,
329
330 #define ASSEMBLY_REF_TABLE_DESC (ASSEMBLY_OS_TABLE_DESC + 4)
331         /* 0x23 AssemblyRef */
332         COL_UINT16, /*Major*/
333         COL_UINT16, /*Minor*/
334         COL_UINT16, /*Build*/
335         COL_UINT16, /*Revision*/
336         COL_UINT32, /*Flags*/
337         COL_BLOB, /*PublicKeyOrToken*/
338         COL_STRING, /*Name*/
339         COL_STRING, /*Culture*/
340         COL_BLOB, /*HashValue*/
341         COL_LAST,
342
343 #define ASSEMBLY_REF_PROCESSOR_TABLE_DESC (ASSEMBLY_REF_TABLE_DESC + 10)
344         /* 0x24 AssemblyRefProcessor */
345         COL_UINT32, /*Processor*/
346         COL_ASSEMBLY_REF, /*AssemblyRef*/
347         COL_LAST,
348
349 #define ASSEMBLY_REF_OS_TABLE_DESC (ASSEMBLY_REF_PROCESSOR_TABLE_DESC + 3)
350         /* 0x25 AssemblyRefOS */
351         COL_UINT32, /*OSPlatformID*/
352         COL_UINT32, /*OSMajorVersion*/
353         COL_UINT32, /*OSMinorVersion*/
354         COL_ASSEMBLY_REF, /*AssemblyRef*/
355         COL_LAST,
356
357 #define FILE_TABLE_DESC (ASSEMBLY_REF_OS_TABLE_DESC + 5)
358         /* 0x26 File */
359         COL_UINT32, /*Flags*/
360         COL_STRING, /*Name*/
361         COL_BLOB, /*HashValue*/
362         COL_LAST,
363
364 #define EXPORTED_TYPE_TABLE_DESC (FILE_TABLE_DESC + 4)
365         /* 0x27 ExportedType */
366         COL_UINT32, /*Flags*/
367         COL_UINT32, /*TypeDefId*/
368         COL_STRING, /*TypeName*/
369         COL_STRING, /*TypeNamespace*/
370         COL_IMPLEMENTATION, /*Implementation*/
371         COL_LAST,
372
373 #define MANIFEST_RESOURCE_TABLE_DESC (EXPORTED_TYPE_TABLE_DESC + 6)
374         /* 0x28 ManifestResource  */
375         COL_UINT32, /*Offset*/
376         COL_UINT32, /*Flags*/
377         COL_STRING, /*Name*/
378         COL_IMPLEMENTATION, /*Implementation*/
379         COL_LAST,
380
381 #define NESTED_CLASS_TABLE_DESC (MANIFEST_RESOURCE_TABLE_DESC + 5)
382         /* 0x29 NestedClass  */
383         COL_TYPE_DEF, /*NestedClass*/
384         COL_TYPE_DEF, /*EnclosingClass*/
385         COL_LAST,
386
387 #define GENERIC_PARAM_TABLE_DESC (NESTED_CLASS_TABLE_DESC + 3)
388         /* 0x2A GenericParam  */
389         COL_UINT16, /*Number*/
390         COL_UINT16, /*Flags*/
391         COL_TYPE_OR_METHOD_DEF, /*Owner*/
392         COL_STRING, /*Name*/
393         COL_LAST,
394
395 #define METHOD_SPEC_TABLE_DESC (GENERIC_PARAM_TABLE_DESC + 5)
396         /* 0x2B MethodSpec  */
397         COL_METHOD_DEF_OR_REF, /*Method*/
398         COL_BLOB, /*Instantiation*/
399         COL_LAST,
400
401 #define GENERIC_PARAM_CONSTRAINT_TABLE_DESC (METHOD_SPEC_TABLE_DESC + 3)
402         /* 0x2C GenericParamConstraint  */
403         COL_GENERIC_PARAM, /*Owner*/
404         COL_TYPE_DEF_OR_REF, /*Constraint*/
405         COL_LAST,
406 };
407
408 const static unsigned char table_desc_start [] = {
409         MODULE_TABLE_DESC,
410         TYPEREF_TABLE_DESC,
411         TYPEDEF_TABLE_DESC,
412         TABLE_03_DESC,
413         FIELD_TABLE_DESC,
414         TABLE_05_DESC,
415         METHODDEF_TABLE_DESC,
416         TABLE_07_DESC,
417         PARAM_TABLE_DESC,
418         INTERFACE_IMPL_TABLE_DESC,
419         MEMBERREF_TABLE_DESC,
420         CONSTANT_TABLE_DESC,
421         CUSTOM_ATTRIBUTE_TABLE_DESC,
422         FIELD_MARSHAL_TABLE_DESC,
423         DECL_SECURITY_TABLE_DESC,
424         CLASS_LAYOUT_TABLE_DESC,
425         FIELD_LAYOUT_TABLE_DESC,
426         STANDARD_ALONE_SIG_TABLE_DESC,
427         EVENT_MAP_TABLE_DESC,
428         TABLE_13_DESC,
429         EVENT_TABLE_DESC,
430         PROPERTY_MAP_TABLE_DESC,
431         TABLE_16_DESC,
432         PROPERTY_TABLE_DESC,
433         METHOD_SEMANTICS_TABLE_DESC,
434         METHOD_IMPL_TABLE_DESC,
435         MODULE_REF_TABLE_DESC,
436         TYPESPEC_TABLE_DESC,
437         IMPL_MAP_TABLE_DESC,
438         FIELD_RVA_TABLE_DESC,
439         TABLE_1E_DESC,
440         TABLE_1F_DESC,
441         ASSEMBLY_TABLE_DESC,
442         ASSEMBLY_PROCESSOR_TABLE_DESC,
443         ASSEMBLY_OS_TABLE_DESC,
444         ASSEMBLY_REF_TABLE_DESC,
445         ASSEMBLY_REF_PROCESSOR_TABLE_DESC,
446         ASSEMBLY_REF_OS_TABLE_DESC,
447         FILE_TABLE_DESC,
448         EXPORTED_TYPE_TABLE_DESC,
449         MANIFEST_RESOURCE_TABLE_DESC,
450         NESTED_CLASS_TABLE_DESC,
451         GENERIC_PARAM_TABLE_DESC,
452         METHOD_SPEC_TABLE_DESC,
453         GENERIC_PARAM_CONSTRAINT_TABLE_DESC
454 };
455
456 #define INVALID_TABLE (0xFF)
457 /*format: number of bits, number of tables, tables{n. tables} */
458 const static unsigned char coded_index_desc[] = {
459 #define TYPEDEF_OR_REF_DESC (0)
460         2, /*bits*/
461         3, /*tables*/
462         MONO_TABLE_TYPEDEF,
463         MONO_TABLE_TYPEREF,
464         MONO_TABLE_TYPESPEC,
465
466 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
467         2, /*bits*/
468         3, /*tables*/
469         MONO_TABLE_FIELD,
470         MONO_TABLE_PARAM,
471         MONO_TABLE_PROPERTY,
472
473 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
474         5, /*bits*/
475         19, /*tables*/
476         MONO_TABLE_METHOD,
477         MONO_TABLE_FIELD,
478         MONO_TABLE_TYPEREF,
479         MONO_TABLE_TYPEDEF,
480         MONO_TABLE_PARAM,
481         MONO_TABLE_INTERFACEIMPL,
482         MONO_TABLE_MEMBERREF,
483         MONO_TABLE_MODULE,
484         MONO_TABLE_DECLSECURITY,
485         MONO_TABLE_PROPERTY, 
486         MONO_TABLE_EVENT,
487         MONO_TABLE_STANDALONESIG,
488         MONO_TABLE_MODULEREF,
489         MONO_TABLE_TYPESPEC,
490         MONO_TABLE_ASSEMBLY,
491         MONO_TABLE_ASSEMBLYREF,
492         MONO_TABLE_FILE,
493         MONO_TABLE_EXPORTEDTYPE,
494         MONO_TABLE_MANIFESTRESOURCE,
495
496 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 21)
497         1, /*bits*/
498         2, /*tables*/
499         MONO_TABLE_FIELD,
500         MONO_TABLE_PARAM,
501
502 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
503         2, /*bits*/
504         3, /*tables*/
505         MONO_TABLE_TYPEDEF,
506         MONO_TABLE_METHOD,
507         MONO_TABLE_ASSEMBLY,
508
509 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
510         3, /*bits*/
511         5, /*tables*/
512         MONO_TABLE_TYPEDEF,
513         MONO_TABLE_TYPEREF,
514         MONO_TABLE_MODULE,
515         MONO_TABLE_METHOD,
516         MONO_TABLE_TYPESPEC,
517
518 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
519         1, /*bits*/
520         2, /*tables*/
521         MONO_TABLE_EVENT,
522         MONO_TABLE_PROPERTY,
523
524 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
525         1, /*bits*/
526         2, /*tables*/
527         MONO_TABLE_METHOD,
528         MONO_TABLE_MEMBERREF,
529
530 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
531         1, /*bits*/
532         2, /*tables*/
533         MONO_TABLE_FIELD,
534         MONO_TABLE_METHOD,
535
536 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
537         2, /*bits*/
538         3, /*tables*/
539         MONO_TABLE_FILE,
540         MONO_TABLE_ASSEMBLYREF,
541         MONO_TABLE_EXPORTEDTYPE,
542
543 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
544         3, /*bits*/
545         5, /*tables*/
546         INVALID_TABLE,
547         INVALID_TABLE,
548         MONO_TABLE_METHOD,
549         MONO_TABLE_MEMBERREF,
550         INVALID_TABLE,
551
552 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
553         2, /*bits*/
554         4, /*tables*/
555         MONO_TABLE_MODULE,
556         MONO_TABLE_MODULEREF,
557         MONO_TABLE_ASSEMBLYREF,
558         MONO_TABLE_TYPEREF,
559
560 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
561         1, /*bits*/
562         2, /*tables*/
563         MONO_TABLE_TYPEDEF,
564         MONO_TABLE_METHOD
565 };
566
567 typedef struct {
568         guint32 rva;
569         guint32 size;
570         guint32 translated_offset;
571 } DataDirectory;
572
573 typedef struct {
574         guint32 offset;
575         guint32 size;
576 } OffsetAndSize;
577
578 typedef struct {
579         guint32 baseRVA;
580         guint32 baseOffset;
581         guint32 size;
582         guint32 rellocationsRVA;
583         guint16 numberOfRelocations;
584 } SectionHeader;
585
586 typedef struct {
587         guint32 row_count;
588         guint32 row_size;
589         guint32 offset;
590 } TableInfo;
591
592 typedef struct {
593         const char *data;
594         guint32 size;
595         GSList *errors;
596         int valid;
597         guint32 section_count, tables_offset;
598         SectionHeader *sections;
599         gboolean wide_strings, wide_guid, wide_blob;
600
601         DataDirectory data_directories [16];
602         OffsetAndSize metadata_streams [5]; //offset from begin of the image
603         TableInfo tables [MONO_TABLE_NUM];
604         guint32 field_sizes [COL_LAST];
605         gboolean is_corlib;
606 } VerifyContext;
607
608 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception)    \
609         do {    \
610                 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1);      \
611                 vinfo->info.status = __status;  \
612                 vinfo->info.message = ( __msg); \
613                 vinfo->exception_type = (__exception);  \
614                 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo);     \
615         } while (0)
616
617
618 #define ADD_ERROR(__ctx, __msg) \
619         do {    \
620                 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
621                 (__ctx)->valid = 0; \
622                 return; \
623         } while (0)
624
625 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
626
627 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
628
629 static guint32
630 pe_signature_offset (VerifyContext *ctx)
631 {
632         return read32 (ctx->data + 0x3c);
633 }
634
635 static guint32
636 pe_header_offset (VerifyContext *ctx)
637 {
638         return read32 (ctx->data + 0x3c) + 4;
639 }
640
641 static gboolean
642 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
643 {
644         int i;
645
646         if (!ctx->sections)
647                 return FALSE;
648
649         for (i = 0; i < ctx->section_count; ++i) {
650                 guint32 base = ctx->sections [i].baseRVA;
651                 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
652                 if (rva >= base && rva + size <= end)
653                         return TRUE;
654         }
655         return FALSE;
656 }
657
658 static gboolean
659 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
660 {
661         if (dir->translated_offset > offset)
662                 return FALSE;
663         if (dir->size < size)
664                 return FALSE;
665         return offset + size <= dir->translated_offset + dir->size;
666 }
667
668 static gboolean
669 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
670 {
671         if (off->offset > offset)
672                 return FALSE;
673         
674         if (off->size < size)
675                 return FALSE;
676
677         return offset + size <= off->offset + off->size;
678 }
679
680 static guint32
681 translate_rva (VerifyContext *ctx, guint32 rva)
682 {
683         int i;
684
685         if (!ctx->sections)
686                 return FALSE;
687
688         for (i = 0; i < ctx->section_count; ++i) {
689                 guint32 base = ctx->sections [i].baseRVA;
690                 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
691                 if (rva >= base && rva <= end) {
692                         guint32 res = (rva - base) + ctx->sections [i].baseOffset;
693                         /* double check */
694                         return res >= ctx->size ? INVALID_OFFSET : res;
695                 }
696         }
697
698         return INVALID_OFFSET;
699 }
700
701 static void
702 verify_msdos_header (VerifyContext *ctx)
703 {
704         guint32 lfanew;
705         if (ctx->size < 128)
706                 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
707         if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
708                 ADD_ERROR (ctx,  g_strdup ("Invalid MS-DOS watermark"));
709         lfanew = pe_signature_offset (ctx);
710         if (lfanew > ctx->size - 4)
711                 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
712 }
713
714 static void
715 verify_pe_header (VerifyContext *ctx)
716 {
717         guint32 offset = pe_signature_offset (ctx);
718         const char *pe_header = ctx->data + offset;
719         if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
720                 ADD_ERROR (ctx,  g_strdup ("Invalid PE header watermark"));
721         pe_header += 4;
722         offset += 4;
723
724         if (offset > ctx->size - 20)
725                 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
726         if (read16 (pe_header) != 0x14c)
727                 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
728 }
729
730 static void
731 verify_pe_optional_header (VerifyContext *ctx)
732 {
733         guint32 offset = pe_header_offset (ctx);
734         guint32 header_size, file_alignment;
735         const char *pe_header = ctx->data + offset;
736         const char *pe_optional_header = pe_header + 20;
737
738         header_size = read16 (pe_header + 16);
739         offset += 20;
740
741         if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
742                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
743
744         if (offset > ctx->size - header_size || header_size > ctx->size)
745                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
746
747         if (read16 (pe_optional_header) == 0x10b) {
748                 if (header_size != 224)
749                         ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
750
751                 /* LAMESPEC MS plays around this value and ignore it during validation
752                 if (read32 (pe_optional_header + 28) != 0x400000)
753                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
754                 if (read32 (pe_optional_header + 32) != 0x2000)
755                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
756                 file_alignment = read32 (pe_optional_header + 36);
757                 if (file_alignment != 0x200 && file_alignment != 0x1000)
758                         ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
759                 /* All the junk in the middle is irrelevant, specially for mono. */
760                 if (read32 (pe_optional_header + 92) > 0x10)
761                         ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
762         } else {
763                 if (read16 (pe_optional_header) == 0x20B)
764                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
765                 else
766                         ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
767         }
768 }
769
770 static void
771 load_section_table (VerifyContext *ctx)
772 {
773         int i;
774         SectionHeader *sections;
775         guint32 offset =  pe_header_offset (ctx);
776         const char *ptr = ctx->data + offset;
777         guint16 num_sections = ctx->section_count = read16 (ptr + 2);
778
779         offset += 244;/*FIXME, this constant is different under PE32+*/
780         ptr += 244;
781
782         if (num_sections * 40 > ctx->size - offset)
783                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
784
785         sections = ctx->sections = g_new0 (SectionHeader, num_sections);
786         for (i = 0; i < num_sections; ++i) {
787                 sections [i].size = read32 (ptr + 8);
788                 sections [i].baseRVA = read32 (ptr + 12);
789                 sections [i].baseOffset = read32 (ptr + 20);
790                 sections [i].rellocationsRVA = read32 (ptr + 24);
791                 sections [i].numberOfRelocations = read16 (ptr + 32);
792                 ptr += 40;
793         }
794
795         ptr = ctx->data + offset; /*reset it to the beggining*/
796         for (i = 0; i < num_sections; ++i) {
797                 guint32 raw_size, flags;
798                 if (sections [i].baseOffset == 0)
799                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
800                 if (sections [i].baseOffset >= ctx->size)
801                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
802                 if (sections [i].size > ctx->size - sections [i].baseOffset)
803                         ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
804
805                 raw_size = read32 (ptr + 16);
806                 if (raw_size < sections [i].size)
807                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
808
809                 if (raw_size > ctx->size - sections [i].baseOffset)
810                         ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
811
812                 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
813                         ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
814
815                 flags = read32 (ptr + 36);
816                 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
817                 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
818                         ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
819
820                 ptr += 40;
821         }
822 }
823
824 static gboolean
825 is_valid_data_directory (int i)
826 {
827         /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
828         return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6; 
829 }
830
831 static void
832 load_data_directories (VerifyContext *ctx)
833 {
834         guint32 offset =  pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
835         const char *ptr = ctx->data + offset;
836         int i;
837
838         for (i = 0; i < 16; ++i) {
839                 guint32 rva = read32 (ptr);
840                 guint32 size = read32 (ptr + 4);
841
842                 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
843                         ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
844
845                 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
846                         ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
847
848                 ctx->data_directories [i].rva = rva;
849                 ctx->data_directories [i].size = size;
850                 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
851
852                 ptr += 8;
853         }
854 }
855
856 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
857
858 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
859
860 static void
861 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
862 {
863         const char *ptr;
864         guint32 hint_table_rva;
865
866         import_rva = translate_rva (ctx, import_rva);
867         g_assert (import_rva != INVALID_OFFSET);
868
869         hint_table_rva = read32 (ctx->data + import_rva);
870         if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
871                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
872
873         hint_table_rva = translate_rva (ctx, hint_table_rva);
874         g_assert (hint_table_rva != INVALID_OFFSET);
875         ptr = ctx->data + hint_table_rva + 2;
876
877         if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
878                 char name[SIZE_OF_CORMAIN];
879                 memcpy (name, ptr, SIZE_OF_CORMAIN);
880                 name [SIZE_OF_CORMAIN - 1] = 0;
881                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
882         }
883 }
884
885 static void
886 verify_import_table (VerifyContext *ctx)
887 {
888         DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
889         guint32 offset = it.translated_offset;
890         const char *ptr = ctx->data + offset;
891         guint32 name_rva, ilt_rva, iat_rva;
892
893         g_assert (offset != INVALID_OFFSET);
894
895         if (it.size < 40)
896                 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
897
898         ilt_rva = read32 (ptr);
899         if (!bounds_check_virtual_address (ctx, ilt_rva, 8))
900                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
901
902         name_rva = read32 (ptr + 12);
903         if (!bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
904                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
905
906         iat_rva = read32 (ptr + 16);
907         if (!bounds_check_virtual_address (ctx, iat_rva, 8))
908                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
909
910         if (iat_rva != ctx->data_directories [IAT_IDX].rva)
911                 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));
912
913         name_rva = translate_rva (ctx, name_rva);
914         g_assert (name_rva != INVALID_OFFSET);
915         ptr = ctx->data + name_rva;
916
917         if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
918                 char name[SIZE_OF_MSCOREE];
919                 memcpy (name, ptr, SIZE_OF_MSCOREE);
920                 name [SIZE_OF_MSCOREE - 1] = 0;
921                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
922         }
923         
924         verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
925         CHECK_ERROR ();
926         verify_hint_name_table (ctx, iat_rva, "Import Address Table");
927 }
928
929 static void
930 verify_resources_table (VerifyContext *ctx)
931 {
932         DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
933         guint32 offset;
934         guint16 named_entries, id_entries;
935         const char *ptr, *root, *end;
936
937         if (it.rva == 0)
938                 return;
939
940         if (it.size < 16)
941                 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));
942
943         offset = it.translated_offset;
944         root = ptr = ctx->data + offset;
945         end = root + it.size;
946
947         g_assert (offset != INVALID_OFFSET);
948
949         named_entries = read16 (ptr + 12);
950         id_entries = read16 (ptr + 14);
951
952         if ((named_entries + id_entries) * 8 + 16 > it.size)
953                 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));
954
955         /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource () 
956         if (named_entries || id_entries)
957                 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
958         */
959 }
960
961 static void
962 verify_cli_header (VerifyContext *ctx)
963 {
964         DataDirectory it = ctx->data_directories [CLI_HEADER_IDX];
965         guint32 offset;
966         const char *ptr;
967         int i;
968
969         if (it.rva == 0)
970                 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
971
972         if (it.size != 72)
973                 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
974
975         offset = it.translated_offset;
976         ptr = ctx->data + offset;
977
978         g_assert (offset != INVALID_OFFSET);
979
980         if (read16 (ptr) != 72)
981                 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
982
983         if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
984                 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
985
986         if (!read32 (ptr + 8) || !read32 (ptr + 12))
987                 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
988
989         if ((read32 (ptr + 16) & ~0x0001000B) != 0)
990                 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
991
992         ptr += 24;
993         for (i = 0; i < 6; ++i) {
994                 guint32 rva = read32 (ptr);
995                 guint32 size = read32 (ptr + 4);
996
997                 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
998                         ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
999
1000                 ptr += 8;
1001
1002                 if (rva && i > 1)
1003                         ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
1004         }
1005 }
1006
1007 static guint32
1008 pad4 (guint32 offset)
1009 {
1010         if (offset & 0x3) //pad to the next 4 byte boundary
1011                 offset = (offset & ~0x3) + 4;
1012         return offset;
1013 }
1014
1015 static void
1016 verify_metadata_header (VerifyContext *ctx)
1017 {
1018         int i;
1019         DataDirectory it = ctx->data_directories [CLI_HEADER_IDX];
1020         guint32 offset;
1021         const char *ptr;
1022
1023         offset = it.translated_offset;
1024         ptr = ctx->data + offset;
1025         g_assert (offset != INVALID_OFFSET);
1026
1027         //build a directory entry for the metadata root
1028         ptr += 8;
1029         it.rva = read32 (ptr);
1030         ptr += 4;
1031         it.size = read32 (ptr);
1032         it.translated_offset = offset = translate_rva (ctx, it.rva);
1033
1034         ptr = ctx->data + offset;
1035         g_assert (offset != INVALID_OFFSET);
1036
1037         if (it.size < 20)
1038                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
1039
1040         if (read32 (ptr) != 0x424A5342)
1041                 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
1042
1043         offset = pad4 (offset + 16 + read32 (ptr + 12));
1044
1045         if (!bounds_check_datadir (&it, offset, 4))
1046                 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));
1047
1048         ptr = ctx->data + offset; //move to streams header 
1049
1050         if (read16 (ptr + 2) != 5)
1051                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section have %d streams (it must have exactly 5)", read16 (ptr + 2)));
1052
1053         ptr += 4;
1054         offset += 4;
1055
1056         for (i = 0; i < 5; ++i) {
1057                 guint32 stream_off, stream_size;
1058                 int string_size, stream_idx;
1059
1060                 if (!bounds_check_datadir (&it, offset, 8))
1061                         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));
1062
1063                 stream_off = it.translated_offset + read32 (ptr);
1064                 stream_size = read32 (ptr + 4);
1065
1066                 if (!bounds_check_datadir (&it,  stream_off, stream_size))
1067                         ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
1068
1069                 ptr += 8;
1070                 offset += 8;
1071
1072                 for (string_size = 0; string_size < 32; ++string_size) {
1073                         if (!bounds_check_datadir (&it, offset++, 1))
1074                                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
1075                         if (!ptr [string_size])
1076                                 break;
1077                 }
1078
1079                 if (ptr [string_size])
1080                         ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
1081
1082                 if (!strncmp ("#Strings", ptr, 9))
1083                         stream_idx = STRINGS_STREAM;
1084                 else if (!strncmp ("#US", ptr, 4))
1085                         stream_idx = USER_STRINGS_STREAM;
1086                 else if (!strncmp ("#Blob", ptr, 6))
1087                         stream_idx = BLOB_STREAM;
1088                 else if (!strncmp ("#GUID", ptr, 6))
1089                         stream_idx = GUID_STREAM;
1090                 else if (!strncmp ("#~", ptr, 3))
1091                         stream_idx = TILDE_STREAM;
1092                 else
1093                         ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
1094
1095                 if (ctx->metadata_streams [stream_idx].offset != 0)
1096                         ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
1097
1098                 ctx->metadata_streams [stream_idx].offset = stream_off;
1099                 ctx->metadata_streams [stream_idx].size = stream_size;
1100
1101                 offset = pad4 (offset);
1102                 ptr = ctx->data + offset;
1103         }
1104 }
1105
1106 static void
1107 verify_tables_schema (VerifyContext *ctx)
1108 {
1109         OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
1110         unsigned offset = tables_area.offset;
1111         const char *ptr = ctx->data + offset;
1112         guint64 valid_tables;
1113         guint32 count;
1114         int i;
1115
1116         if (tables_area.size < 24)
1117                 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
1118
1119         if (ptr [4] != 2)
1120                 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
1121         if (ptr [5] != 0)
1122                 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
1123
1124         if ((ptr [6] & ~0x7) != 0)
1125                 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]));
1126
1127         ctx->wide_strings = ptr [6] & 0x1;
1128         ctx->wide_guid = ptr [6] & 0x2;
1129         ctx->wide_blob = ptr [6] & 04;
1130
1131         valid_tables = read64 (ptr + 8);
1132         count = 0;
1133         for (i = 0; i < 64; ++i) {
1134                 if (!(valid_tables & ((guint64)1 << i)))
1135                         continue;
1136
1137                 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
1138                   Unused: 0x1E 0x1F 0x2D-0x3F
1139                   We don't care about the MS extensions.*/
1140                 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
1141                         ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
1142                 if (i == 0x1E || i == 0x1F || i >= 0x2D)
1143                         ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
1144                 ++count;
1145         }
1146
1147         if (tables_area.size < 24 + count * 4)
1148                 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));
1149
1150         ptr += 24;
1151
1152         for (i = 0; i < 64; ++i) {
1153                 if (valid_tables & ((guint64)1 << i)) {
1154                         ctx->tables [i].row_count = read32 (ptr);
1155                         ptr += 4;
1156                 }
1157         }
1158         ctx->tables_offset = offset + 24 + count * 4;
1159 }
1160
1161 static guint32
1162 enc_index_size (guint32 bits, guint32 max)
1163 {
1164         guint32 size = 1 << (16 - bits); 
1165         return max >= size ? 4 : 2;
1166 }
1167
1168 static void
1169 calc_fields_size (VerifyContext *ctx)
1170 {
1171 #define TS(T) (ctx->tables [T].row_count)
1172 #define MAX2(TA,TB) MAX (TS (TA), TS (TB))
1173 #define MAX3(TA,TB,TC) MAX (TS (TA), MAX (TS (TB), TS (TC)))
1174 #define TB_SIZE(T) (TS (T) >= (1 << 16) ? 4 : 2)
1175
1176         int tmp;
1177         memset (ctx->field_sizes, 0, sizeof (guint32) * COL_LAST);
1178         
1179         ctx->field_sizes [COL_UINT8] = 1;
1180         ctx->field_sizes [COL_UINT16] = 2;
1181         ctx->field_sizes [COL_UINT32] = 4;
1182
1183         ctx->field_sizes [COL_STRING] = ctx->wide_strings ? 4 : 2;
1184         ctx->field_sizes [COL_GUID] = ctx->wide_guid ? 4 : 2;
1185         ctx->field_sizes [COL_BLOB] = ctx->wide_blob? 4 : 2;
1186
1187         ctx->field_sizes [COL_TYPE_DEF_OR_REF] = enc_index_size (2, MAX3 (MONO_TABLE_TYPEDEF, MONO_TABLE_TYPEREF, MONO_TABLE_TYPESPEC));
1188         ctx->field_sizes [COL_HAS_CONSTANT] = enc_index_size (2, MAX3 (MONO_TABLE_FIELD, MONO_TABLE_PARAM, MONO_TABLE_PROPERTY));
1189
1190         tmp = MAX3 (MONO_TABLE_METHOD, MONO_TABLE_FIELD, MONO_TABLE_TYPEREF);
1191         tmp = MAX (tmp, MAX3 (MONO_TABLE_TYPEDEF, MONO_TABLE_PARAM, MONO_TABLE_INTERFACEIMPL));
1192         tmp = MAX (tmp, MAX3 (MONO_TABLE_MEMBERREF, MONO_TABLE_MODULE, MONO_TABLE_DECLSECURITY));
1193         tmp = MAX (tmp, MAX3 (MONO_TABLE_PROPERTY, MONO_TABLE_EVENT, MONO_TABLE_STANDALONESIG));
1194         tmp = MAX (tmp, MAX3 (MONO_TABLE_MODULEREF, MONO_TABLE_TYPESPEC, MONO_TABLE_ASSEMBLY));
1195         tmp = MAX (tmp, MAX3 (MONO_TABLE_ASSEMBLYREF, MONO_TABLE_FILE, MONO_TABLE_EXPORTEDTYPE));
1196         tmp = MAX (tmp, MONO_TABLE_MANIFESTRESOURCE);
1197         ctx->field_sizes [COL_HAS_CATTR] = enc_index_size (5, tmp);
1198
1199         ctx->field_sizes [COL_HAS_FIELD_MARSHAL] = enc_index_size (1, MAX2 (MONO_TABLE_FIELD, MONO_TABLE_PARAM));
1200         ctx->field_sizes [COL_HAS_DECL_SECURITY] = enc_index_size (2, MAX3 (MONO_TABLE_TYPEDEF, MONO_TABLE_METHOD, MONO_TABLE_ASSEMBLY));
1201
1202         tmp = MAX3 (MONO_TABLE_TYPEDEF, MONO_TABLE_TYPEREF, MONO_TABLE_MODULEREF);
1203         tmp = MAX (tmp, MAX2 (MONO_TABLE_METHOD, MONO_TABLE_TYPESPEC));
1204         ctx->field_sizes [COL_MEMBER_REF_PARENT] = enc_index_size (3, tmp);
1205
1206         ctx->field_sizes [COL_HAS_SEMANTICS] = enc_index_size (1, MAX2 (MONO_TABLE_EVENT, MONO_TABLE_PROPERTY));
1207         ctx->field_sizes [COL_METHOD_DEF_OR_REF] = enc_index_size (1, MAX2 (MONO_TABLE_METHOD, MONO_TABLE_MEMBERREF));
1208         ctx->field_sizes [COL_MEMBER_FORWARDED] = enc_index_size (1, MAX2 (MONO_TABLE_FIELD, MONO_TABLE_METHOD));
1209         ctx->field_sizes [COL_IMPLEMENTATION] = enc_index_size (2, MAX3 (MONO_TABLE_FILE, MONO_TABLE_ASSEMBLYREF, MONO_TABLE_EXPORTEDTYPE));
1210
1211         ctx->field_sizes [COL_CATTR_TYPE] = enc_index_size (3, MAX2 (MONO_TABLE_METHOD, MONO_TABLE_MEMBERREF));
1212         ctx->field_sizes [COL_RES_SCOPE] = enc_index_size (2, MAX (MAX2 (MONO_TABLE_MODULE, MONO_TABLE_MODULEREF), MAX2 (MONO_TABLE_ASSEMBLYREF, MONO_TABLE_TYPEREF))); 
1213         ctx->field_sizes [COL_TYPE_OR_METHOD_DEF] = enc_index_size (1, MAX2 (MONO_TABLE_TYPEDEF, MONO_TABLE_METHOD));
1214
1215         ctx->field_sizes [COL_TYPE_DEF] = TB_SIZE (MONO_TABLE_TYPEDEF);
1216         ctx->field_sizes [COL_METHOD_DEF] = TB_SIZE (MONO_TABLE_METHOD);
1217         ctx->field_sizes [COL_FIELD] = TB_SIZE (MONO_TABLE_FIELD);
1218         ctx->field_sizes [COL_PARAM] = TB_SIZE (MONO_TABLE_PARAM);
1219         ctx->field_sizes [COL_PROPERTY] = TB_SIZE (MONO_TABLE_PROPERTY);
1220         ctx->field_sizes [COL_EVENT] = TB_SIZE (MONO_TABLE_EVENT);
1221         ctx->field_sizes [COL_GENERIC_PARAM] = TB_SIZE (MONO_TABLE_GENERICPARAM);
1222         ctx->field_sizes [COL_ASSEMBLY_REF] = TB_SIZE (MONO_TABLE_ASSEMBLYREF);
1223         ctx->field_sizes [COL_MODULE_REF] = TB_SIZE (MONO_TABLE_MODULEREF);
1224
1225 }
1226
1227 static guint32
1228 calc_row_size (VerifyContext *ctx)
1229 {
1230         int i, idx;
1231         guint64 total_size = 0;
1232         guint32 offset = ctx->tables_offset;
1233
1234         for (idx = 0, i = 0; i < 0x2D; ++i) {
1235                 int size = 0, type;
1236
1237                 while ((type = table_desc [idx++]) != COL_LAST)
1238                         size += ctx->field_sizes [type];
1239
1240                 ctx->tables [i].row_size = size;
1241                 ctx->tables [i].offset = offset;
1242                 total_size += (guint64)size * ctx->tables [i].row_count;
1243                 offset += size * ctx->tables [i].row_count;
1244         }
1245
1246         if (total_size > 0xFFFFFFFF)
1247                 return 0;
1248
1249         return (guint32)total_size; 
1250 }
1251
1252 static void
1253 decode_row (VerifyContext *ctx, int desc_offset, TableInfo *table, int row, guint32 *res)
1254 {
1255         const unsigned char *data = (unsigned char *)(ctx->data + table->offset);
1256         data += table->row_size * row;
1257
1258         while (table_desc [desc_offset] != COL_LAST) {
1259                 switch (ctx->field_sizes [table_desc [desc_offset++]]) {
1260                 case 1:
1261                         *res++ = *data++; 
1262                         break;
1263                 case 2:
1264                         *res++ = read16 (data);
1265                         data += 2;
1266                         break;
1267                 case 4:
1268                         *res++ = read32 (data);
1269                         data += 4;
1270                         break;
1271                 default:
1272                         g_assert_not_reached ();
1273                 }
1274         }
1275 }
1276
1277 static guint32
1278 get_col_offset (VerifyContext *ctx, int table, int column)
1279 {
1280         guint32 desc_offset = table_desc_start [table];
1281         guint32 offset = 0;
1282
1283         while (column-- > 0)
1284                 offset += ctx->field_sizes [table_desc [desc_offset++]];
1285
1286         return offset;
1287 }
1288
1289 static guint32
1290 get_col_size (VerifyContext *ctx, int table, int column)
1291 {
1292         guint32 desc_offset = table_desc_start [table];
1293         guint32 type = table_desc [desc_offset + column];
1294         VERIFIER_DEBUG ( printf ("get_col_size table %d column %d type %d size %d\n", table, column, type, ctx->field_sizes [type]));
1295
1296
1297         return ctx->field_sizes [type];
1298 }
1299
1300 static gboolean
1301 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
1302 {
1303         OffsetAndSize strings = ctx->metadata_streams [STRINGS_STREAM];
1304         glong length;
1305         const char *data = ctx->data + strings.offset;
1306         if (offset >= strings.size)
1307                 return FALSE;
1308         if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing  
1309                 return FALSE;
1310
1311         if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
1312                 return FALSE;
1313         return length > 0;
1314 }
1315
1316 static gboolean
1317 is_valid_guid (VerifyContext *ctx, guint32 offset)
1318 {
1319         OffsetAndSize guids = ctx->metadata_streams [GUID_STREAM];
1320         return guids.size >= 8 && guids.size - 8 >= offset;
1321 }
1322
1323 static guint32
1324 get_coded_index_token (VerifyContext *ctx, int token_kind, guint32 coded_token)
1325 {
1326         guint32 bits = coded_index_desc [token_kind];
1327         return coded_token >> bits;
1328 }
1329
1330 static guint32
1331 make_coded_token (int kind, guint32 table, guint32 table_idx)
1332 {
1333         guint32 bits = coded_index_desc [kind++];
1334         guint32 tables = coded_index_desc [kind++];
1335         guint32 i;
1336         for (i = 0; i < tables; ++i) {
1337                 if (coded_index_desc [kind++] == table)
1338                         return ((table_idx + 1) << bits) | i; 
1339         }
1340         g_assert_not_reached ();
1341         return -1;
1342 }
1343
1344 static gboolean
1345 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
1346 {
1347         guint32 bits = coded_index_desc [token_kind++];
1348         guint32 table_count = coded_index_desc [token_kind++];
1349         guint32 table = coded_token & ((1 << bits) - 1);
1350         guint32 token = coded_token >> bits;
1351
1352         if (table >= table_count)
1353                 return FALSE;
1354
1355         /*token_kind points to the first table idx*/
1356         table = coded_index_desc [token_kind + table];
1357
1358         if (table == INVALID_TABLE)
1359                 return FALSE;
1360         return token <= ctx->tables [table].row_count;
1361 }
1362
1363 typedef struct {
1364         guint32 token;
1365         guint32 col_size;
1366         guint32 col_offset;
1367 } RowLocator;
1368
1369 static int
1370 token_locator (const void *a, const void *b)
1371 {
1372         RowLocator *loc = (RowLocator *)a;
1373         unsigned const char *row = (unsigned const char *)b;
1374         guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1375
1376         VERIFIER_DEBUG ( printf ("\tfound token %x\n", token) );
1377         return (int)loc->token - (int)token;
1378 }
1379
1380 static int
1381 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1382 {
1383         TableInfo *tinfo = &ctx->tables [table];
1384         RowLocator locator;
1385         const char *res, *base;
1386         locator.token = coded_token;
1387         locator.col_offset = get_col_offset (ctx, table, column);
1388         locator.col_size = get_col_size (ctx, table, column);
1389         base = ctx->data + tinfo->offset;
1390
1391         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) );
1392         res = bsearch (&locator, base, tinfo->row_count, tinfo->row_size, token_locator);
1393         if (!res)
1394                 return -1;
1395
1396         return (res - base) / tinfo->row_count;
1397 }
1398
1399 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1400 static int
1401 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1402 {
1403         if (offset == 0)
1404                 return strcmp (str, "");
1405
1406         return strcmp (str, ctx->data + ctx->metadata_streams [STRINGS_STREAM].offset + offset);
1407 }
1408
1409 static gboolean
1410 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1411 {
1412         return ctx->is_corlib && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAME]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAMESPACE]);
1413 }
1414
1415 static void
1416 verify_module_table (VerifyContext *ctx)
1417 {
1418         TableInfo *table = &ctx->tables [MONO_TABLE_MODULE];
1419         guint32 data [MONO_MODULE_SIZE];
1420
1421         if (table->row_count != 1)
1422                 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->row_count));
1423
1424         decode_row (ctx, MODULE_TABLE_DESC, table, 0, data);
1425
1426         if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1427                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1428
1429         if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1430                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1431
1432         if (data [MONO_MODULE_ENC] != 0)
1433                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1434
1435         if (data [MONO_MODULE_ENCBASE] != 0)
1436                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1437 }
1438
1439 static void
1440 verify_typeref_table (VerifyContext *ctx)
1441 {
1442         TableInfo *table = &ctx->tables [MONO_TABLE_TYPEREF];
1443         guint32 data [MONO_TYPEREF_SIZE];
1444         int i;
1445
1446         for (i = 0; i < table->row_count; ++i) {
1447                 decode_row (ctx, TYPEREF_TABLE_DESC, table, i, data);
1448                 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1449                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1450                 
1451                 if (!get_coded_index_token (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1452                         ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1453
1454                 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1455                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1456
1457                 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1458                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
1459         }
1460 }
1461
1462 /*bits 9,11,14,15,19,21,24-31 */
1463 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 9) | (1 << 11) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
1464 static void
1465 verify_typedef_table (VerifyContext *ctx)
1466 {
1467         TableInfo *table = &ctx->tables [MONO_TABLE_TYPEDEF];
1468         guint32 data [MONO_TYPEDEF_SIZE];
1469         guint32 fieldlist = 1, methodlist = 1;
1470         int i;
1471
1472         if (table->row_count == 0)
1473                 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
1474
1475         for (i = 0; i < table->row_count; ++i) {
1476                 decode_row (ctx, TYPEDEF_TABLE_DESC, table, i, data);
1477                 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
1478                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
1479
1480                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
1481                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
1482
1483                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
1484                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1485
1486                 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
1487                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1488
1489                 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
1490                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
1491
1492                 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1493                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
1494
1495                 if (i == 0) {
1496                         if (data [MONO_TYPEDEF_EXTENDS] != 0)
1497                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
1498                 } else {
1499                         if (typedef_is_system_object (ctx, data) && data [MONO_TYPEDEF_EXTENDS] != 0)
1500                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
1501         
1502                         if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
1503                                 if (data [MONO_TYPEDEF_EXTENDS])
1504                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
1505                                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
1506                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
1507                         } else {
1508                                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1509                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
1510         
1511                                 if (!get_coded_index_token (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS])) 
1512                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
1513                         }
1514                 }
1515
1516                 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
1517                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
1518
1519                 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
1520                         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));
1521
1522                 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
1523                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
1524
1525                 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
1526                         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));
1527
1528                 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
1529                 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
1530         }
1531 }
1532
1533 /*bits 3,11,14 */
1534 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
1535 static void
1536 verify_field_table (VerifyContext *ctx)
1537 {
1538         TableInfo *table = &ctx->tables [MONO_TABLE_FIELD];
1539         guint32 data [MONO_TABLE_FIELD], flags;
1540         int i;
1541
1542         for (i = 0; i < table->row_count; ++i) {
1543                 decode_row (ctx, FIELD_TABLE_DESC, table, i, data);
1544                 flags = data [MONO_FIELD_FLAGS];
1545
1546                 if (flags & INVALID_FIELD_FLAG_BITS)
1547                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
1548
1549                 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)         
1550                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
1551
1552                 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
1553                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
1554
1555                 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
1556                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
1557
1558                 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
1559                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
1560
1561                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
1562                                 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
1563                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
1564
1565                 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
1566                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1567                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1568
1569                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
1570                                 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
1571                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1572
1573                 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
1574                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
1575
1576         }
1577 }
1578
1579 static void
1580 verify_tables_data (VerifyContext *ctx)
1581 {
1582         OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
1583         guint table_area_size;
1584         calc_fields_size (ctx);
1585         table_area_size = calc_row_size (ctx);
1586
1587         if (table_area_size == 0)
1588                 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
1589
1590         if (!bounds_check_offset (&tables_area, ctx->tables_offset, table_area_size))
1591                 ADD_ERROR (ctx, g_strdup_printf ("Tables data require %d bytes but the only %d are available in the #~ stream", table_area_size, tables_area.size - (ctx->tables_offset - tables_area.offset)));
1592
1593         verify_module_table (ctx);
1594         CHECK_ERROR ();
1595         verify_typeref_table (ctx);
1596         CHECK_ERROR ();
1597         verify_typedef_table (ctx);
1598         CHECK_ERROR ();
1599         verify_field_table (ctx);
1600 }
1601
1602 GSList*
1603 mono_image_verify (const char *data, guint32 size, gboolean is_corlib)
1604 {
1605         VerifyContext ctx;
1606         memset (&ctx, 0, sizeof (VerifyContext));
1607         ctx.data = data;
1608         ctx.size = size;
1609         ctx.valid = 1;
1610         ctx.is_corlib = is_corlib;
1611
1612         verify_msdos_header (&ctx);
1613         CHECK_STATE();
1614         verify_pe_header (&ctx);
1615         CHECK_STATE();
1616         verify_pe_optional_header (&ctx);
1617         CHECK_STATE();
1618         load_section_table (&ctx);
1619         CHECK_STATE();
1620         load_data_directories (&ctx);
1621         CHECK_STATE();
1622         verify_import_table (&ctx);
1623         CHECK_STATE();
1624         /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
1625         verify_resources_table (&ctx);
1626         CHECK_STATE();
1627         verify_cli_header (&ctx);
1628         CHECK_STATE();
1629         verify_metadata_header (&ctx);
1630         CHECK_STATE();
1631         verify_tables_schema (&ctx);
1632         CHECK_STATE();
1633         verify_tables_data (&ctx);
1634         CHECK_STATE();
1635 cleanup:
1636         g_free (ctx.sections);
1637         return ctx.errors;
1638 }