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