Handle cattr with arrays of System.Type.
[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 == 0x50 || etype == MONO_TYPE_CLASS) {
1860                                 klass = mono_defaults.systemtype_class;
1861                         } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1862                                 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
1863                                 klass = mono_class_from_mono_type (&simple_type);
1864                         } else
1865                                 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1866
1867                         type = MONO_TYPE_SZARRAY;
1868                         goto handle_enum;
1869                 }
1870                 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type));
1871         }
1872
1873
1874         case MONO_TYPE_CLASS:
1875                 if (klass != mono_defaults.systemtype_class)
1876                         FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1877                 *_ptr = ptr;
1878                 return is_valid_ser_string (ctx, _ptr, end);
1879
1880         case MONO_TYPE_VALUETYPE:
1881                 if (!klass || !klass->enumtype)
1882                         FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass->name_space, klass->name));
1883
1884                 klass = klass->element_class;
1885                 type = klass->byval_arg.type;
1886                 goto handle_enum;
1887
1888         case MONO_TYPE_SZARRAY:
1889                 mono_type = &klass->byval_arg;
1890                 if (!is_valid_cattr_type (mono_type))
1891                         FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass->name_space, klass->name));
1892                 if (!safe_read32 (element_count, ptr, end))
1893                         FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1894                 if (element_count == 0xFFFFFFFFu) {
1895                         *_ptr = ptr;
1896                         return TRUE;
1897                 }
1898                 for (i = 0; i < element_count; ++i) {
1899                         if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
1900                                 return FALSE;
1901                 }
1902                 *_ptr = ptr;
1903                 return TRUE;
1904         default:
1905                 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
1906         }
1907
1908         if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
1909                 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
1910         *_ptr = ptr + elem_size;
1911         return TRUE;
1912 }
1913
1914 static gboolean
1915 is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
1916 {
1917         MonoError error;
1918         unsigned prolog = 0;
1919         const char *end;
1920         MonoMethodSignature *sig;
1921         int args, i;
1922         unsigned num_named;
1923
1924         if (!ctor)
1925                 FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
1926
1927         sig = mono_method_signature_checked (ctor, &error);
1928         if (!mono_error_ok (&error)) {
1929                 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error)));
1930                 mono_error_cleanup (&error);
1931                 return FALSE;
1932         }
1933
1934         if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
1935                 FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1936
1937         end = ptr + size;
1938
1939         if (!safe_read16 (prolog, ptr, end))
1940                 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1941
1942         if (prolog != 1)
1943                 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1944
1945         args = sig->param_count;
1946         for (i = 0; i < args; ++i) {
1947                 MonoType *arg_type = sig->params [i];
1948                 if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
1949                         return FALSE;
1950         }
1951
1952         if (!safe_read16 (num_named, ptr, end))
1953                 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
1954
1955         for (i = 0; i < num_named; ++i) {
1956                 MonoType *type, simple_type = {{0}};
1957                 unsigned kind;
1958
1959                 if (!safe_read8 (kind, ptr, end))
1960                         FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
1961                 if (kind != 0x53 && kind != 0x54)
1962                         FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
1963                 if (!safe_read8 (kind, ptr, end))
1964                         FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
1965
1966                 if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
1967                         simple_type.type = kind;
1968                         type = &simple_type;
1969                 } else if (kind == MONO_TYPE_ENUM) {
1970                         MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
1971                         if (!klass)
1972                                 return FALSE;
1973                         type = &klass->byval_arg;
1974                 } else if (kind == 0x50) {
1975                         type = &mono_defaults.systemtype_class->byval_arg;
1976                 } else if (kind == 0x51) {
1977                         type = &mono_defaults.object_class->byval_arg;
1978                 } else if (kind == MONO_TYPE_SZARRAY) {
1979                         MonoClass *klass;
1980                         unsigned etype = 0;
1981                         if (!safe_read8 (etype, ptr, end))
1982                                 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1983
1984                         if (etype == MONO_TYPE_ENUM) {
1985                                 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1986                                 if (!klass)
1987                                         return FALSE;
1988                         } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
1989                                 klass = mono_defaults.systemtype_class;
1990                         } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1991                                 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
1992                                 klass = mono_class_from_mono_type (&simple_type);
1993                         } else
1994                                 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1995
1996                         type = &mono_array_class_get (klass, 1)->byval_arg;
1997                 } else {
1998                         FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
1999                 }
2000
2001                 if (!is_valid_ser_string (ctx, &ptr, end))
2002                         return FALSE;
2003
2004                 if (!is_valid_fixed_param (ctx, type, &ptr, end))
2005                         return FALSE;
2006
2007         }
2008
2009         return TRUE;
2010 }
2011
2012 static gboolean
2013 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
2014 {
2015         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2016         //TODO do proper verification
2017         return blob.size >= 1 && blob.size - 1 >= offset;
2018 }
2019
2020 static gboolean
2021 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
2022 {
2023         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2024         //TODO do proper verification
2025         return blob.size >= 1 && blob.size - 1 >= offset;
2026 }
2027
2028 static gboolean
2029 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
2030 {
2031         guint32 size = 0;
2032         unsigned signature = 0;
2033         const char *ptr = NULL, *end;
2034
2035         if (!decode_signature_header (ctx, offset, &size, &ptr))
2036                 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
2037         end = ptr + size;
2038
2039         if (!safe_read8 (signature, ptr, end))
2040                 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2041
2042         --ptr;
2043         if (signature == 0x07)
2044                 return parse_locals_signature (ctx, &ptr, end);
2045
2046         /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
2047         if (signature == 0x06)
2048                 return parse_field (ctx, &ptr, end);
2049
2050         return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
2051 }
2052
2053 static gboolean
2054 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
2055 {
2056         guint32 size = 0;
2057         const char *ptr = NULL, *end;
2058
2059         if (!decode_signature_header (ctx, offset, &size, &ptr))
2060                 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
2061         end = ptr + size;
2062
2063         return parse_property_signature (ctx, &ptr, end);
2064 }
2065
2066 static gboolean
2067 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
2068 {
2069         guint32 size = 0;
2070         const char *ptr = NULL, *end;
2071         unsigned type = 0;
2072         
2073         if (!decode_signature_header (ctx, offset, &size, &ptr))
2074                 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
2075         end = ptr + size;
2076
2077         if (!parse_custom_mods (ctx, &ptr, end))
2078                 return FALSE;
2079
2080         if (!safe_read8 (type, ptr, end))
2081                 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
2082
2083         if (type == MONO_TYPE_BYREF) {
2084                 if (!safe_read8 (type, ptr, end)) 
2085                         FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
2086                 if (type == MONO_TYPE_TYPEDBYREF)
2087                         FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
2088         }
2089         
2090         if (type == MONO_TYPE_TYPEDBYREF)
2091                 return TRUE;
2092
2093         --ptr;
2094         return parse_type (ctx, &ptr, end);
2095 }
2096
2097 static gboolean
2098 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
2099 {
2100         guint32 size = 0;
2101         const char *ptr = NULL, *end;
2102         unsigned type = 0;
2103         unsigned count = 0, i;
2104
2105         if (!decode_signature_header (ctx, offset, &size, &ptr))
2106                 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
2107         end = ptr + size;
2108
2109         if (!safe_read8 (type, ptr, end))
2110                 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
2111
2112         if (type != 0x0A)
2113                 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
2114
2115         if (!safe_read_cint (count, ptr, end))
2116                 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
2117
2118         if (!count)
2119                 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
2120
2121         for (i = 0; i < count; ++i) {
2122                 if (!parse_type (ctx, &ptr, end))
2123                         FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
2124         }
2125         return TRUE;
2126 }
2127
2128 static gboolean
2129 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
2130 {
2131         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2132         guint32 entry_size, bytes;
2133
2134         if (blob.size < offset)
2135                 return FALSE;
2136
2137         if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2138                 return FALSE;
2139
2140         if (entry_size < minsize)
2141                 return FALSE;
2142
2143         if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
2144                 return FALSE;
2145         entry_size += bytes;
2146
2147         return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
2148 }
2149
2150 static gboolean
2151 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
2152 {
2153         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2154         guint32 size, entry_size, bytes;
2155
2156         if (blob.size < offset)
2157                 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
2158         
2159         if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2160                 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
2161
2162         if (type == MONO_TYPE_STRING) {
2163                 //String is encoded as: compressed_int:len len *bytes
2164                 offset += bytes;
2165
2166                 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
2167                         FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));  
2168
2169                 return TRUE;
2170         }
2171
2172         switch (type) {
2173         case MONO_TYPE_BOOLEAN:
2174         case MONO_TYPE_I1:
2175         case MONO_TYPE_U1:
2176                 size = 1;
2177                 break;
2178         case MONO_TYPE_CHAR:
2179         case MONO_TYPE_I2:
2180         case MONO_TYPE_U2:
2181                 size = 2;
2182                 break;
2183         case MONO_TYPE_I4:
2184         case MONO_TYPE_U4:
2185         case MONO_TYPE_R4:
2186         case MONO_TYPE_CLASS:
2187                 size = 4;
2188                 break;
2189
2190         case MONO_TYPE_I8:
2191         case MONO_TYPE_U8:
2192         case MONO_TYPE_R8:
2193                 size = 8;
2194                 break;
2195         default:
2196                 g_assert_not_reached ();
2197         }
2198
2199         if (size != entry_size)
2200                 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
2201
2202         offset += bytes;
2203
2204         if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
2205                 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
2206
2207         if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
2208                 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
2209         return TRUE;
2210 }
2211
2212 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
2213 //only 0x01, 0x40 and 0x80 are allowed
2214 #define SECTION_HEADER_INVALID_FLAGS 0x3E
2215
2216 static gboolean
2217 is_valid_method_header (VerifyContext *ctx, guint32 rva, guint32 *locals_token)
2218 {
2219         unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
2220         unsigned header = 0;
2221         unsigned fat_header = 0, size = 0, max_stack;
2222         const char *ptr = NULL, *end;
2223
2224         *locals_token = 0;
2225
2226         if (offset == INVALID_ADDRESS)
2227                 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
2228
2229         ptr = ctx->data + offset;
2230         end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
2231
2232         if (!safe_read8 (header, ptr, end))
2233                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
2234
2235         switch (header & 0x3) {
2236         case 0:
2237         case 1:
2238                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
2239         case 2:
2240                 header >>= 2;
2241                 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end)) 
2242                         FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
2243                 return TRUE;
2244         }
2245         //FAT HEADER
2246         --ptr;
2247         if (!safe_read16 (fat_header, ptr, end))
2248                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
2249
2250         size = (fat_header >> 12) & 0xF;
2251         if (size != 3)
2252                 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
2253
2254         if (!safe_read16 (max_stack, ptr, end))
2255                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
2256
2257         if (!safe_read32 (code_size, ptr, end))
2258                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
2259
2260         if (!safe_read32 (local_vars_tok, ptr, end))
2261                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
2262
2263         if (local_vars_tok) {
2264                 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
2265                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
2266                 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)   
2267                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
2268                 if (!(local_vars_tok & 0xFFFFFF))
2269                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature with zero index"));
2270                 *locals_token = local_vars_tok & 0xFFFFFF;
2271         }
2272
2273         if (fat_header & FAT_HEADER_INVALID_FLAGS)
2274                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
2275
2276         if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
2277                 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
2278
2279         if (!(fat_header & 0x08))
2280                 return TRUE;
2281
2282         ptr += code_size;
2283
2284         do {
2285                 unsigned section_header = 0, section_size = 0;
2286                 gboolean is_fat;
2287
2288                 ptr = dword_align (ptr);
2289                 if (!safe_read32 (section_header, ptr, end))
2290                         FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
2291
2292                 if (section_header & SECTION_HEADER_INVALID_FLAGS)
2293                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
2294                         
2295                 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
2296                 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
2297
2298                 if (section_size < 4)
2299                         FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
2300
2301                 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
2302                         FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
2303
2304                 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
2305                         guint32 i, clauses = section_size / (is_fat ? 24 : 12);
2306                         /*
2307                                 LAMEIMPL: MS emits section_size without accounting for header size.
2308                                 Mono does as the spec says. section_size is header + section
2309                                 MS's peverify happily accepts both. 
2310                         */
2311                         if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
2312                                 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)));
2313
2314                         /* only verify the class token is verified as the rest is done by the IL verifier*/
2315                         for (i = 0; i < clauses; ++i) {
2316                                 unsigned flags = *(unsigned char*)ptr;
2317                                 unsigned class_token = 0;
2318                                 ptr += (is_fat ? 20 : 8);
2319                                 if (!safe_read32 (class_token, ptr, end))
2320                                         FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
2321                                 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
2322                                         guint table = mono_metadata_token_table (class_token);
2323                                         if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
2324                                                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
2325                                         if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
2326                                                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
2327                                 }
2328                         }
2329                 }
2330
2331                 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
2332                         break;
2333         } while (1);
2334         return TRUE;
2335 }
2336
2337 static void
2338 verify_module_table (VerifyContext *ctx)
2339 {
2340         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
2341         guint32 data [MONO_MODULE_SIZE];
2342
2343         if (table->rows != 1)
2344                 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
2345
2346         mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
2347
2348         if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
2349                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
2350
2351         if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
2352                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
2353
2354         if (data [MONO_MODULE_ENC] != 0)
2355                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
2356
2357         if (data [MONO_MODULE_ENCBASE] != 0)
2358                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
2359 }
2360
2361 static void
2362 verify_typeref_table (VerifyContext *ctx)
2363 {
2364         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2365         MonoError error;
2366         guint32 i;
2367
2368         for (i = 0; i < table->rows; ++i) {
2369                 mono_verifier_verify_typeref_row (ctx->image, i, &error);
2370                 add_from_mono_error (ctx, &error);
2371         }
2372 }
2373
2374 /*bits 9,11,14,15,19,21,24-31 */
2375 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2376 static void
2377 verify_typedef_table (VerifyContext *ctx)
2378 {
2379         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2380         guint32 data [MONO_TYPEDEF_SIZE];
2381         guint32 fieldlist = 1, methodlist = 1, visibility;
2382         int i;
2383
2384         if (table->rows == 0)
2385                 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2386
2387         for (i = 0; i < table->rows; ++i) {
2388                 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2389                 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2390                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2391
2392                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2393                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2394
2395                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2396                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2397
2398                 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2399                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2400
2401                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2402                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2403
2404                 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2405                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2406
2407                 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2408                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2409
2410                 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2411                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2412
2413                 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2414                 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2415                         search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2416                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2417
2418                 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2419                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2420
2421                 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2422                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2423
2424                 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2425                         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));
2426
2427                 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2428                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2429
2430                 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2431                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2432
2433                 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2434                         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));
2435
2436                 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2437                 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2438         }
2439 }
2440
2441 static void
2442 verify_typedef_table_full (VerifyContext *ctx)
2443 {
2444         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2445         guint32 data [MONO_TYPEDEF_SIZE];
2446         int i;
2447
2448         if (table->rows == 0)
2449                 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2450
2451         for (i = 0; i < table->rows; ++i) {
2452                 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2453
2454                 if (i == 0) {
2455                         /*XXX it's ok if <module> extends object, or anything at all, actually. */
2456                         /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
2457                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2458                         */
2459                         continue;
2460                 }
2461
2462                 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2463                         if (data [MONO_TYPEDEF_EXTENDS])
2464                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2465                 } else {
2466                         gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2467                         gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2468
2469                         if (is_sys_obj) {
2470                                 if (has_parent)
2471                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2472                         } else {
2473                                 if (!has_parent) {
2474                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2475                                 }
2476                         }
2477                 }
2478         }
2479 }
2480
2481 /*bits 3,11,14 */
2482 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2483 static void
2484 verify_field_table (VerifyContext *ctx)
2485 {
2486         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2487         guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2488         int i;
2489
2490         module_field_list = (guint32)-1;
2491         if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2492                 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2493                 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2494         }
2495         
2496         for (i = 0; i < table->rows; ++i) {
2497                 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2498                 flags = data [MONO_FIELD_FLAGS];
2499
2500                 if (flags & INVALID_FIELD_FLAG_BITS)
2501                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2502
2503                 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)         
2504                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2505
2506                 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2507                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2508
2509                 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2510                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2511
2512                 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2513                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2514
2515                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2516                                 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2517                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2518
2519                 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
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 has Default but there is no corresponding row in the Constant table", i));
2522
2523                 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2524                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2525                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2526
2527                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2528                                 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2529                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2530
2531                 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2532                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2533
2534                 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2535                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2536
2537                 //TODO verify contant flag
2538
2539                 if (i + 1 < module_field_list) {
2540                         guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2541                         if (!(flags & FIELD_ATTRIBUTE_STATIC))
2542                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2543                         if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2544                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2545                 }
2546         }
2547 }
2548
2549 static void
2550 verify_field_table_full (VerifyContext *ctx)
2551 {
2552         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2553         guint32 data [MONO_FIELD_SIZE];
2554         int i;
2555         
2556         for (i = 0; i < table->rows; ++i) {
2557                 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2558
2559                 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2560                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2561         }
2562 }
2563
2564 /*bits 8,9,10,11,13,14,15*/
2565 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2566 static void
2567 verify_method_table (VerifyContext *ctx)
2568 {
2569         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2570         guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2571         guint32 paramlist = 1;
2572         gboolean is_ctor, is_cctor;
2573         const char *name;
2574         int i;
2575
2576         module_method_list = (guint32)-1;
2577         if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2578                 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2579                 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2580         }
2581
2582         for (i = 0; i < table->rows; ++i) {
2583                 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2584                 rva = data [MONO_METHOD_RVA];
2585                 implflags = data [MONO_METHOD_IMPLFLAGS];
2586                 flags = data [MONO_METHOD_FLAGS];
2587                 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2588                 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2589                 
2590
2591                 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2592                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2593
2594                 if (access == 0x7)
2595                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2596
2597                 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2598                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2599
2600                 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2601                 is_ctor = !strcmp (".ctor", name);
2602                 is_cctor = !strcmp (".cctor", name);
2603
2604                 if ((is_ctor || is_cctor) &&
2605                         search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2606                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2607
2608                 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2609                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2610                 
2611                 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2612                         if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2613                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2614                         if (flags & METHOD_ATTRIBUTE_FINAL)
2615                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2616                         if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2617                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2618                 }
2619
2620                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2621                         ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2622
2623                 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2624                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2625
2626                 //XXX no checks against cas stuff 10,11,12,13)
2627
2628                 //TODO check iface with .ctor (15,16)
2629
2630                 if (i + 1 < module_method_list) {
2631                         if (!(flags & METHOD_ATTRIBUTE_STATIC))
2632                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2633                         if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2634                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2635                         if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2636                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2637                 }
2638
2639                 //TODO check valuetype for synchronized
2640
2641                 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2642                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2643
2644                 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2645                         if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2646                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2647                         if (!(flags & METHOD_ATTRIBUTE_STATIC))
2648                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2649                 }
2650
2651                 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && 
2652                                 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2653                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2654
2655                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2656                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2657
2658                 //TODO check signature contents
2659
2660                 if (rva) {
2661                         if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2662                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2663                         if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2664                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2665                 } else {
2666                         if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2667                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2668                 }
2669
2670                 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2671                         if (rva)
2672                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2673                         if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2674                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2675                 }
2676                 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2677                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2678
2679                 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2680                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2681
2682                 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2683                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2684
2685                 if (data [MONO_METHOD_PARAMLIST] == 0)
2686                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2687
2688                 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2689                         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));
2690
2691                 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2692                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2693
2694                 paramlist = data [MONO_METHOD_PARAMLIST];
2695
2696         }
2697 }
2698
2699 static void
2700 verify_method_table_full (VerifyContext *ctx)
2701 {
2702         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2703         guint32 data [MONO_METHOD_SIZE], rva, locals_token;
2704         int i;
2705
2706         for (i = 0; i < table->rows; ++i) {
2707                 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2708                 rva = data [MONO_METHOD_RVA];
2709
2710                 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2711                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2712
2713                 if (rva && !is_valid_method_header (ctx, rva, &locals_token))
2714                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2715         }
2716 }
2717
2718 static guint32
2719 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2720 {
2721         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2722         guint32 row = *current_method;
2723         guint32 paramlist, tmp;
2724
2725
2726         paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2727         while (row < table->rows) {
2728                 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2729                 if (tmp > paramlist) {
2730                         *current_method = row;
2731                         return tmp - paramlist;
2732                 }
2733                 ++row;
2734         }
2735
2736         /*no more methods, all params apply to the last one*/
2737         *current_method = table->rows;
2738         return (guint32)-1;
2739 }
2740
2741
2742 #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))
2743 static void
2744 verify_param_table (VerifyContext *ctx)
2745 {
2746         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2747         guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2748         gboolean first_param = TRUE;
2749         int i;
2750
2751         if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2752                 if (table->rows > 0)
2753                         ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2754                 return;
2755         }
2756         
2757         remaining_params = get_next_param_count (ctx, &current_method);
2758
2759         for (i = 0; i < table->rows; ++i) {
2760                 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2761                 flags = data [MONO_PARAM_FLAGS];
2762
2763                 if (flags & INVALID_PARAM_FLAGS_BITS)
2764                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2765
2766                 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2767                         if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2768                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2769                 } else {
2770                         if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2771                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2772                 }
2773
2774                 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)
2775                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2776
2777                 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2778                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2779
2780                 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2781                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2782
2783                 first_param = FALSE;
2784                 sequence = data [MONO_PARAM_SEQUENCE];
2785                 if (--remaining_params == 0) {
2786                         remaining_params = get_next_param_count (ctx, &current_method);
2787                         first_param = TRUE;
2788                 }
2789         }
2790 }
2791
2792 static void
2793 verify_interfaceimpl_table (VerifyContext *ctx)
2794 {
2795         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2796         guint32 data [MONO_INTERFACEIMPL_SIZE];
2797         int i;
2798
2799         for (i = 0; i < table->rows; ++i) {
2800                 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2801                 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2802                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2803
2804                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2805                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2806
2807                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2808                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2809         }
2810 }
2811
2812 static void
2813 verify_memberref_table (VerifyContext *ctx)
2814 {
2815         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2816         guint32 data [MONO_MEMBERREF_SIZE];
2817         int i;
2818
2819         for (i = 0; i < table->rows; ++i) {
2820                 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2821
2822                 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2823                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2824
2825                 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2826                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2827
2828                 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2829                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2830
2831                 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2832                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2833         }
2834 }
2835
2836
2837 static void
2838 verify_memberref_table_full (VerifyContext *ctx)
2839 {
2840         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2841         guint32 data [MONO_MEMBERREF_SIZE];
2842         int i;
2843
2844         for (i = 0; i < table->rows; ++i) {
2845                 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2846
2847                 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2848                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field  0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2849         }
2850 }
2851
2852 static void
2853 verify_constant_table (VerifyContext *ctx)
2854 {
2855         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2856         guint32 data [MONO_CONSTANT_SIZE], type;
2857         int i;
2858
2859         for (i = 0; i < table->rows; ++i) {
2860                 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2861                 type = data [MONO_CONSTANT_TYPE];
2862
2863                 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2864                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2865
2866                 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2867                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2868
2869                 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2870                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2871
2872                 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2873                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2874         }
2875 }
2876
2877 static void
2878 verify_cattr_table (VerifyContext *ctx)
2879 {
2880         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2881         guint32 data [MONO_CUSTOM_ATTR_SIZE];
2882         int i;
2883
2884         for (i = 0; i < table->rows; ++i) {
2885                 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2886
2887                 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2888                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2889
2890                 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]))
2891                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Type field 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2892
2893                 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2894                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2895         }
2896 }
2897
2898 static void
2899 verify_cattr_table_full (VerifyContext *ctx)
2900 {
2901         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2902         MonoMethod *ctor;
2903         const char *ptr;
2904         guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2905         int i;
2906
2907         for (i = 0; i < table->rows; ++i) {
2908                 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2909
2910                 if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2911                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2912
2913                 mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2914                 switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2915                 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2916                         mtoken |= MONO_TOKEN_METHOD_DEF;
2917                         break;
2918                 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2919                         mtoken |= MONO_TOKEN_MEMBER_REF;
2920                         break;
2921                 default:
2922                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2923                 }
2924
2925                 ctor = mono_get_method (ctx->image, mtoken, NULL);
2926
2927                 /*This can't fail since this is checked in is_valid_cattr_blob*/
2928                 g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
2929
2930                 if (!is_valid_cattr_content (ctx, ctor, ptr, size))
2931                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2932         }
2933 }
2934
2935 static void
2936 verify_field_marshal_table (VerifyContext *ctx)
2937 {
2938         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2939         guint32 data [MONO_FIELD_MARSHAL_SIZE];
2940         int i;
2941
2942         for (i = 0; i < table->rows; ++i) {
2943                 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2944
2945                 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2946                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2947
2948                 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2949                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2950
2951                 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2952                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2953
2954                 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2955                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2956         }
2957 }
2958
2959 static void
2960 verify_field_marshal_table_full (VerifyContext *ctx)
2961 {
2962         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2963         guint32 data [MONO_FIELD_MARSHAL_SIZE];
2964         int i;
2965
2966         for (i = 0; i < table->rows; ++i) {
2967                 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2968
2969                 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2970                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2971         }
2972 }
2973
2974 static void
2975 verify_decl_security_table (VerifyContext *ctx)
2976 {
2977         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2978         guint32 data [MONO_DECL_SECURITY_SIZE];
2979         int i;
2980
2981         for (i = 0; i < table->rows; ++i) {
2982                 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2983
2984                 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2985                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2986
2987                 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2988                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2989
2990                 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2991                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2992         }
2993 }
2994
2995 static void
2996 verify_decl_security_table_full (VerifyContext *ctx)
2997 {
2998         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2999         guint32 data [MONO_DECL_SECURITY_SIZE];
3000         int i;
3001
3002         for (i = 0; i < table->rows; ++i) {
3003                 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3004
3005                 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
3006                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
3007         }
3008 }
3009
3010 static void
3011 verify_class_layout_table (VerifyContext *ctx)
3012 {
3013         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
3014         guint32 data [MONO_CLASS_LAYOUT_SIZE];
3015         int i;
3016
3017         for (i = 0; i < table->rows; ++i) {
3018                 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
3019
3020                 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3021                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
3022
3023                 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
3024                 case 0:
3025                 case 1:
3026                 case 2:
3027                 case 4:
3028                 case 8:
3029                 case 16:
3030                 case 32:
3031                 case 64:
3032                 case 128:
3033                         break;
3034                 default:
3035                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3036                 }
3037         }
3038 }
3039
3040 static void
3041 verify_field_layout_table (VerifyContext *ctx)
3042 {
3043         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3044         guint32 data [MONO_FIELD_LAYOUT_SIZE];
3045         int i;
3046
3047         for (i = 0; i < table->rows; ++i) {
3048                 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
3049
3050                 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3051                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
3052         }
3053 }
3054
3055 static void
3056 verify_standalonesig_table (VerifyContext *ctx)
3057 {
3058         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3059         guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3060         int i;
3061
3062         for (i = 0; i < table->rows; ++i) {
3063                 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3064
3065                 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
3066                         ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3067         }
3068 }
3069
3070 static void
3071 verify_standalonesig_table_full (VerifyContext *ctx)
3072 {
3073         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3074         guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3075         int i;
3076
3077         for (i = 0; i < table->rows; ++i) {
3078                 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3079
3080                 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
3081                         ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3082         }
3083 }
3084
3085 static void
3086 verify_eventmap_table (VerifyContext *ctx)
3087 {
3088         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3089         guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3090         int i;
3091
3092         for (i = 0; i < table->rows; ++i) {
3093                 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
3094
3095                 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3096                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
3097
3098                 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
3099                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
3100
3101                 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
3102         }
3103 }
3104
3105 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3106 static void
3107 verify_event_table (VerifyContext *ctx)
3108 {
3109         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3110         guint32 data [MONO_EVENT_SIZE];
3111         int i;
3112
3113         for (i = 0; i < table->rows; ++i) {
3114                 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3115
3116                 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
3117                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
3118
3119                 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
3120                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
3121
3122                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
3123                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
3124         }
3125 }
3126
3127 static void
3128 verify_event_table_full (VerifyContext *ctx)
3129 {
3130         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3131         MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
3132         guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
3133         gboolean found_add, found_remove;
3134         int i, idx;
3135
3136         for (i = 0; i < table->rows; ++i) {
3137                 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3138
3139                 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
3140                 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
3141                 if (idx == -1)
3142                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
3143
3144                 //first we move to the first row for this event
3145                 while (idx > 0) {
3146                         if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3147                                 break;
3148                         --idx;
3149                 }
3150                 //now move forward looking for AddOn and RemoveOn rows
3151                 found_add = found_remove = FALSE;
3152                 while (idx < sema_table->rows) {
3153                         mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
3154                         if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
3155                                 break;
3156                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3157                                 found_add = TRUE;
3158                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3159                                 found_remove = TRUE;
3160                         if (found_add && found_remove)
3161                                 break;
3162                         ++idx;
3163                 }
3164
3165                 if (!found_add)
3166                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3167                 if (!found_remove)
3168                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3169         }
3170 }
3171
3172 static void
3173 verify_propertymap_table (VerifyContext *ctx)
3174 {
3175         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3176         guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3177         int i;
3178
3179         for (i = 0; i < table->rows; ++i) {
3180                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
3181
3182                 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3183                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
3184
3185                 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
3186                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
3187
3188                 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
3189         }
3190 }
3191
3192 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3193 static void
3194 verify_property_table (VerifyContext *ctx)
3195 {
3196         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3197         guint32 data [MONO_PROPERTY_SIZE];
3198         int i;
3199
3200         for (i = 0; i < table->rows; ++i) {
3201                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
3202
3203                 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
3204                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
3205
3206                 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
3207                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
3208
3209                 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
3210                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
3211
3212                 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
3213                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
3214                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
3215
3216         }
3217 }
3218
3219 static void
3220 verify_methodimpl_table (VerifyContext *ctx)
3221 {
3222         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3223         guint32 data [MONO_METHODIMPL_SIZE];
3224         int i;
3225
3226         for (i = 0; i < table->rows; ++i) {
3227                 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3228
3229                 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3230                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3231                         
3232                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3233                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3234                 
3235                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3236                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3237
3238                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3239                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3240                 
3241                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3242                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3243         }
3244 }
3245
3246 static void
3247 verify_moduleref_table (VerifyContext *ctx)
3248 {
3249         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3250         guint32 data [MONO_MODULEREF_SIZE];
3251         int i;
3252
3253         for (i = 0; i < table->rows; ++i) {
3254                 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
3255
3256                 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
3257                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3258         }
3259 }
3260
3261 static void
3262 verify_typespec_table (VerifyContext *ctx)
3263 {
3264         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3265         guint32 data [MONO_TYPESPEC_SIZE];
3266         int i;
3267
3268         for (i = 0; i < table->rows; ++i) {
3269                 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3270
3271                 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
3272                         ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3273         }
3274 }
3275
3276 static void
3277 verify_typespec_table_full (VerifyContext *ctx)
3278 {
3279         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3280         guint32 data [MONO_TYPESPEC_SIZE];
3281         int i;
3282
3283         for (i = 0; i < table->rows; ++i) {
3284                 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3285                 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
3286                 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
3287                         ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3288         }
3289         ctx->token = 0;
3290 }
3291
3292 #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))
3293 static void
3294 verify_implmap_table (VerifyContext *ctx)
3295 {
3296         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3297         guint32 data [MONO_IMPLMAP_SIZE], cconv;
3298         int i;
3299
3300         for (i = 0; i < table->rows; ++i) {
3301                 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
3302
3303                 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
3304                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
3305
3306                 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
3307                 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
3308                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
3309
3310                 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3311                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
3312
3313                 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
3314                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
3315
3316                 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3317                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
3318
3319                 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
3320                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
3321
3322                 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows)
3323                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
3324         }
3325 }
3326
3327 static void
3328 verify_fieldrva_table (VerifyContext *ctx)
3329 {
3330         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3331         guint32 data [MONO_FIELD_RVA_SIZE];
3332         int i;
3333
3334         for (i = 0; i < table->rows; ++i) {
3335                 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
3336
3337                 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
3338                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
3339
3340                 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3341                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
3342         }
3343 }
3344
3345 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
3346 static void
3347 verify_assembly_table (VerifyContext *ctx)
3348 {
3349         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3350         guint32 data [MONO_ASSEMBLY_SIZE], hash;
3351         int i;
3352
3353         if (table->rows > 1)
3354                 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
3355
3356         for (i = 0; i < table->rows; ++i) {
3357                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
3358
3359                 hash = data [MONO_ASSEMBLY_HASH_ALG];
3360                 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
3361                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
3362
3363                 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
3364                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3365
3366                 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
3367                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3368
3369                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3370                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3371
3372                 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3373                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3374         }
3375 }
3376
3377 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
3378 static void
3379 verify_assemblyref_table (VerifyContext *ctx)
3380 {
3381         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3382         guint32 data [MONO_ASSEMBLYREF_SIZE];
3383         int i;
3384
3385         for (i = 0; i < table->rows; ++i) {
3386                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3387
3388                 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3389                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3390
3391                 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3392                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3393
3394                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3395                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3396
3397                 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3398                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3399
3400                 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3401                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3402         }
3403 }
3404
3405 #define INVALID_FILE_FLAGS_BITS ~(1)
3406 static void
3407 verify_file_table (VerifyContext *ctx)
3408 {
3409         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3410         guint32 data [MONO_FILE_SIZE];
3411         int i;
3412
3413         for (i = 0; i < table->rows; ++i) {
3414                 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3415                 
3416                 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3417                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3418
3419                 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3420                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3421
3422                 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3423                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3424         }
3425 }
3426
3427 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3428 static void
3429 verify_exportedtype_table (VerifyContext *ctx)
3430 {
3431         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3432         guint32 data [MONO_EXP_TYPE_SIZE];
3433         int i;
3434
3435         for (i = 0; i < table->rows; ++i) {
3436                 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3437                 
3438                 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3439                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3440
3441                 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3442                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3443
3444                 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3445                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3446
3447                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3448                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3449
3450                 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3451                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3452
3453                 /*nested type can't have a namespace*/
3454                 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3455                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3456         }
3457 }
3458
3459 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3460 static void
3461 verify_manifest_resource_table (VerifyContext *ctx)
3462 {
3463         MonoCLIImageInfo *iinfo = ctx->image->image_info;
3464         MonoCLIHeader *ch = &iinfo->cli_cli_header;
3465         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3466         guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3467         int i;
3468
3469         resources_size = ch->ch_resources.size;
3470
3471         for (i = 0; i < table->rows; ++i) {
3472                 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3473
3474                 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3475                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3476
3477                 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3478                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3479
3480                 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3481                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3482
3483                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3484                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3485
3486                 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3487                 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3488
3489                 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3490                         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])));
3491
3492                 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3493                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3494
3495                 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3496                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3497         }
3498 }
3499
3500 static void
3501 verify_nested_class_table (VerifyContext *ctx)
3502 {
3503         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3504         guint32 data [MONO_NESTED_CLASS_SIZE];
3505         int i;
3506
3507         for (i = 0; i < table->rows; ++i) {
3508                 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3509
3510                 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3511                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3512                 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3513                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3514                 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3515                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass  and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3516         }
3517 }
3518
3519 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3520 static void
3521 verify_generic_param_table (VerifyContext *ctx)
3522 {
3523         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3524         guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3525         int i, param_number = 0;
3526
3527         for (i = 0; i < table->rows; ++i) {
3528                 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3529
3530                 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3531                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3532
3533                 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3534                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3535
3536                 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3537                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3538
3539                 token = data [MONO_GENERICPARAM_OWNER];
3540
3541                 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3542                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3543
3544                 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3545                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3546
3547                 if (token != last_token) {
3548                         param_number = 0;
3549                         last_token = token;
3550                 }
3551
3552                 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3553                         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));
3554
3555                 ++param_number;
3556         }
3557 }
3558
3559 static void
3560 verify_method_spec_table (VerifyContext *ctx)
3561 {
3562         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3563         guint32 data [MONO_METHODSPEC_SIZE];
3564         int i;
3565
3566         for (i = 0; i < table->rows; ++i) {
3567                 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3568
3569                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3570                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3571
3572                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3573                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3574
3575                 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3576                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3577         }
3578 }
3579
3580 static void
3581 verify_method_spec_table_full (VerifyContext *ctx)
3582 {
3583         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3584         guint32 data [MONO_METHODSPEC_SIZE];
3585         int i;
3586
3587         for (i = 0; i < table->rows; ++i) {
3588                 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3589
3590                 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3591                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3592         }
3593 }
3594
3595 static void
3596 verify_generic_param_constraint_table (VerifyContext *ctx)
3597 {
3598         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3599         guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3600         int i;
3601
3602         for (i = 0; i < table->rows; ++i) {
3603                 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3604
3605                 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3606                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3607
3608                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3609                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3610
3611                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3612                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3613         }
3614 }
3615
3616
3617 typedef struct {
3618         const char *name;
3619         const char *name_space;
3620         guint32 resolution_scope;
3621 } TypeDefUniqueId;
3622
3623 static guint
3624 typedef_hash (gconstpointer _key)
3625 {
3626         const TypeDefUniqueId *key = _key;
3627         return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3628 }
3629
3630 static gboolean
3631 typedef_equals (gconstpointer _a, gconstpointer _b)
3632 {
3633         const TypeDefUniqueId *a = _a;
3634         const TypeDefUniqueId *b = _b;
3635         return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3636 }
3637
3638 static void
3639 verify_typedef_table_global_constraints (VerifyContext *ctx)
3640 {
3641         int i;
3642         guint32 data [MONO_TYPEDEF_SIZE];
3643         guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3644         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3645         MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3646         GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3647
3648         for (i = 0; i < table->rows; ++i) {
3649                 guint visibility;
3650                 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3651                 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3652
3653                 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3654                 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3655                 type->resolution_scope = 0;
3656
3657                 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3658                 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3659                         int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3660                         g_assert (res >= 0);
3661
3662                         mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3663                         type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3664                 }
3665
3666                 if (g_hash_table_lookup (unique_types, type)) {
3667                         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));
3668                         g_hash_table_destroy (unique_types);
3669                         g_free (type);
3670                         return;
3671                 }
3672                 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3673         }
3674
3675         g_hash_table_destroy (unique_types);
3676 }
3677
3678 static void
3679 verify_typeref_table_global_constraints (VerifyContext *ctx)
3680 {
3681         int i;
3682         guint32 data [MONO_TYPEREF_SIZE];
3683         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3684         GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3685
3686         for (i = 0; i < table->rows; ++i) {
3687                 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3688                 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3689
3690                 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3691                 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3692                 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3693
3694                 if (g_hash_table_lookup (unique_types, type)) {
3695                         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));
3696                         g_hash_table_destroy (unique_types);
3697                         g_free (type);
3698                         return;
3699                 }
3700                 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3701         }
3702
3703         g_hash_table_destroy (unique_types);
3704 }
3705
3706 static void
3707 verify_tables_data_global_constraints (VerifyContext *ctx)
3708 {
3709         verify_typedef_table_global_constraints (ctx);
3710 }
3711
3712 static void
3713 verify_tables_data_global_constraints_full (VerifyContext *ctx)
3714 {
3715         verify_typeref_table (ctx);
3716         verify_typeref_table_global_constraints (ctx);
3717 }
3718
3719 static void
3720 verify_tables_data (VerifyContext *ctx)
3721 {
3722         OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3723         guint32 size = 0, tables_offset;
3724         int i;
3725
3726         for (i = 0; i < 0x2D; ++i) {
3727                 MonoTableInfo *table = &ctx->image->tables [i];
3728                 guint32 tmp_size;
3729                 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3730                 if (tmp_size < size) {
3731                         size = 0;
3732                         break;
3733                 }
3734                 size = tmp_size;                        
3735         }
3736
3737         if (size == 0)
3738                 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3739
3740         tables_offset = ctx->image->tables_base - ctx->data;
3741         if (!bounds_check_offset (&tables_area, tables_offset, size))
3742                 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)));
3743
3744         verify_module_table (ctx);
3745         CHECK_ERROR ();
3746         /*Obfuscators love to place broken stuff in the typeref table
3747         verify_typeref_table (ctx);
3748         CHECK_ERROR ();*/
3749         verify_typedef_table (ctx);
3750         CHECK_ERROR ();
3751         verify_field_table (ctx);
3752         CHECK_ERROR ();
3753         verify_method_table (ctx);
3754         CHECK_ERROR ();
3755         verify_param_table (ctx);
3756         CHECK_ERROR ();
3757         verify_interfaceimpl_table (ctx);
3758         CHECK_ERROR ();
3759         verify_memberref_table (ctx);
3760         CHECK_ERROR ();
3761         verify_constant_table (ctx);
3762         CHECK_ERROR ();
3763         verify_cattr_table (ctx);
3764         CHECK_ERROR ();
3765         verify_field_marshal_table (ctx);
3766         CHECK_ERROR ();
3767         verify_decl_security_table (ctx);
3768         CHECK_ERROR ();
3769         verify_class_layout_table (ctx);
3770         CHECK_ERROR ();
3771         verify_field_layout_table (ctx);
3772         CHECK_ERROR ();
3773         verify_standalonesig_table (ctx);
3774         CHECK_ERROR ();
3775         verify_eventmap_table (ctx);
3776         CHECK_ERROR ();
3777         verify_event_table (ctx);
3778         CHECK_ERROR ();
3779         verify_propertymap_table (ctx);
3780         CHECK_ERROR ();
3781         verify_property_table (ctx);
3782         CHECK_ERROR ();
3783         verify_methodimpl_table (ctx);
3784         CHECK_ERROR ();
3785         verify_moduleref_table (ctx);
3786         CHECK_ERROR ();
3787         verify_typespec_table (ctx);
3788         CHECK_ERROR ();
3789         verify_implmap_table (ctx);
3790         CHECK_ERROR ();
3791         verify_fieldrva_table (ctx);
3792         CHECK_ERROR ();
3793         verify_assembly_table (ctx);
3794         CHECK_ERROR ();
3795         verify_assemblyref_table (ctx);
3796         CHECK_ERROR ();
3797         verify_file_table (ctx);
3798         CHECK_ERROR ();
3799         verify_exportedtype_table (ctx);
3800         CHECK_ERROR ();
3801         verify_manifest_resource_table (ctx);
3802         CHECK_ERROR ();
3803         verify_nested_class_table (ctx);
3804         CHECK_ERROR ();
3805         verify_generic_param_table (ctx);
3806         CHECK_ERROR ();
3807         verify_method_spec_table (ctx);
3808         CHECK_ERROR ();
3809         verify_generic_param_constraint_table (ctx);
3810         CHECK_ERROR ();
3811         verify_tables_data_global_constraints (ctx);
3812 }
3813
3814 static void
3815 init_verify_context (VerifyContext *ctx, MonoImage *image, gboolean report_error)
3816 {
3817         memset (ctx, 0, sizeof (VerifyContext));
3818         ctx->image = image;
3819         ctx->report_error = report_error;
3820         ctx->report_warning = FALSE; //export this setting in the API
3821         ctx->valid = 1;
3822         ctx->size = image->raw_data_len;
3823         ctx->data = image->raw_data;
3824 }
3825
3826 static gboolean
3827 cleanup_context (VerifyContext *ctx, GSList **error_list)
3828 {
3829         g_free (ctx->sections);
3830         if (error_list)
3831                 *error_list = ctx->errors;
3832         else
3833                 mono_free_verify_list (ctx->errors);
3834         return ctx->valid;      
3835 }
3836
3837 static gboolean
3838 cleanup_context_checked (VerifyContext *ctx, MonoError *error)
3839 {
3840         g_free (ctx->sections);
3841         if (ctx->errors) {
3842                 MonoVerifyInfo *info = ctx->errors->data;
3843                 mono_error_set_bad_image (error, ctx->image, "%s", info->message);
3844                 mono_free_verify_list (ctx->errors);
3845         }
3846         return ctx->valid;
3847 }
3848
3849 gboolean
3850 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3851 {
3852         VerifyContext ctx;
3853
3854         if (!mono_verifier_is_enabled_for_image (image))
3855                 return TRUE;
3856
3857         init_verify_context (&ctx, image, error_list != NULL);
3858         ctx.stage = STAGE_PE;
3859
3860         verify_msdos_header (&ctx);
3861         CHECK_STATE();
3862         verify_pe_header (&ctx);
3863         CHECK_STATE();
3864         verify_pe_optional_header (&ctx);
3865         CHECK_STATE();
3866         load_section_table (&ctx);
3867         CHECK_STATE();
3868         load_data_directories (&ctx);
3869         CHECK_STATE();
3870         verify_import_table (&ctx);
3871         CHECK_STATE();
3872         /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3873         verify_resources_table (&ctx);
3874
3875 cleanup:
3876         return cleanup_context (&ctx, error_list);
3877 }
3878
3879 gboolean
3880 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3881 {
3882         VerifyContext ctx;
3883
3884         if (!mono_verifier_is_enabled_for_image (image))
3885                 return TRUE;
3886
3887         init_verify_context (&ctx, image, error_list != NULL);
3888         ctx.stage = STAGE_CLI;
3889
3890         verify_cli_header (&ctx);
3891         CHECK_STATE();
3892         verify_metadata_header (&ctx);
3893         CHECK_STATE();
3894         verify_tables_schema (&ctx);
3895
3896 cleanup:
3897         return cleanup_context (&ctx, error_list);
3898 }
3899
3900
3901 /*
3902  * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3903  * Other verification checks are meant to be done lazily by the runtime. Those include:
3904  *      blob items (signatures, method headers, custom attributes, etc)
3905  *  type semantics related
3906  *  vtable related
3907  *  stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3908  * 
3909  * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3910  * operation still need more checking.
3911  */
3912 gboolean
3913 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3914 {
3915         VerifyContext ctx;
3916
3917         if (!mono_verifier_is_enabled_for_image (image))
3918                 return TRUE;
3919
3920         init_verify_context (&ctx, image, error_list != NULL);
3921         ctx.stage = STAGE_TABLES;
3922
3923         verify_tables_data (&ctx);
3924
3925         return cleanup_context (&ctx, error_list);
3926 }
3927
3928
3929 /*
3930  * Verifies all other constraints.
3931  */
3932 gboolean
3933 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3934 {
3935         VerifyContext ctx;
3936
3937         if (!mono_verifier_is_enabled_for_image (image))
3938                 return TRUE;
3939
3940         init_verify_context (&ctx, image, error_list != NULL);
3941         ctx.stage = STAGE_TABLES;
3942
3943         verify_typedef_table_full (&ctx);
3944         CHECK_STATE ();
3945         verify_field_table_full (&ctx);
3946         CHECK_STATE ();
3947         verify_method_table_full (&ctx);
3948         CHECK_STATE ();
3949         verify_memberref_table_full (&ctx);
3950         CHECK_STATE ();
3951         verify_cattr_table_full (&ctx);
3952         CHECK_STATE ();
3953         verify_field_marshal_table_full (&ctx);
3954         CHECK_STATE ();
3955         verify_decl_security_table_full (&ctx);
3956         CHECK_STATE ();
3957         verify_standalonesig_table_full (&ctx);
3958         CHECK_STATE ();
3959         verify_event_table_full (&ctx);
3960         CHECK_STATE ();
3961         verify_typespec_table_full (&ctx);
3962         CHECK_STATE ();
3963         verify_method_spec_table_full (&ctx);
3964         CHECK_STATE ();
3965         verify_tables_data_global_constraints_full (&ctx);
3966
3967 cleanup:
3968         return cleanup_context (&ctx, error_list);
3969 }
3970
3971 gboolean
3972 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3973 {
3974         VerifyContext ctx;
3975
3976         if (!mono_verifier_is_enabled_for_image (image))
3977                 return TRUE;
3978
3979         init_verify_context (&ctx, image, error_list != NULL);
3980         ctx.stage = STAGE_TABLES;
3981
3982         is_valid_field_signature (&ctx, offset);
3983         return cleanup_context (&ctx, error_list);
3984 }
3985
3986 gboolean
3987 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3988 {
3989         VerifyContext ctx;
3990         guint32 locals_token;
3991
3992         if (!mono_verifier_is_enabled_for_image (image))
3993                 return TRUE;
3994
3995         init_verify_context (&ctx, image, error_list != NULL);
3996         ctx.stage = STAGE_TABLES;
3997
3998         is_valid_method_header (&ctx, offset, &locals_token);
3999         if (locals_token) {
4000                 guint32 sig_offset = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_STANDALONESIG], locals_token - 1, MONO_STAND_ALONE_SIGNATURE);
4001                 is_valid_standalonesig_blob (&ctx, sig_offset);
4002         }
4003
4004         return cleanup_context (&ctx, error_list);
4005 }
4006
4007 gboolean
4008 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4009 {
4010         VerifyContext ctx;
4011
4012         mono_error_init (error);
4013
4014         if (!mono_verifier_is_enabled_for_image (image))
4015                 return TRUE;
4016
4017         init_verify_context (&ctx, image, TRUE);
4018         ctx.stage = STAGE_TABLES;
4019
4020         is_valid_method_signature (&ctx, offset);
4021         /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
4022         return cleanup_context_checked (&ctx, error);
4023 }
4024
4025 gboolean
4026 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
4027 {
4028         VerifyContext ctx;
4029
4030         if (!mono_verifier_is_enabled_for_image (image))
4031                 return TRUE;
4032
4033         init_verify_context (&ctx, image, error_list != NULL);
4034         ctx.stage = STAGE_TABLES;
4035
4036         is_valid_method_or_field_signature (&ctx, offset);
4037         return cleanup_context (&ctx, error_list);
4038 }
4039
4040 gboolean
4041 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4042 {
4043         VerifyContext ctx;
4044
4045         if (!mono_verifier_is_enabled_for_image (image))
4046                 return TRUE;
4047
4048         init_verify_context (&ctx, image, error_list != NULL);
4049         ctx.stage = STAGE_TABLES;
4050
4051         is_valid_standalonesig_blob (&ctx, offset);
4052         return cleanup_context (&ctx, error_list);
4053 }
4054
4055 gboolean
4056 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4057 {
4058         VerifyContext ctx;
4059
4060         if (!mono_verifier_is_enabled_for_image (image))
4061                 return TRUE;
4062
4063         init_verify_context (&ctx, image, error_list != NULL);
4064         ctx.stage = STAGE_TABLES;
4065         ctx.token = token;
4066
4067         is_valid_typespec_blob (&ctx, offset);
4068         return cleanup_context (&ctx, error_list);
4069 }
4070
4071 gboolean
4072 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4073 {
4074         VerifyContext ctx;
4075
4076         if (!mono_verifier_is_enabled_for_image (image))
4077                 return TRUE;
4078
4079         init_verify_context (&ctx, image, error_list != NULL);
4080         ctx.stage = STAGE_TABLES;
4081
4082         is_valid_methodspec_blob (&ctx, offset);
4083         return cleanup_context (&ctx, error_list);
4084 }
4085
4086 static void
4087 verify_user_string (VerifyContext *ctx, guint32 offset)
4088 {
4089         OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
4090         guint32 entry_size, bytes;
4091
4092         if (heap_us.size < offset)
4093                 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
4094
4095         if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
4096                 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
4097
4098         if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
4099                 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
4100
4101         entry_size += bytes;
4102
4103         if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
4104                 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
4105 }
4106
4107 gboolean
4108 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4109 {
4110         VerifyContext ctx;
4111
4112         if (!mono_verifier_is_enabled_for_image (image))
4113                 return TRUE;
4114
4115         init_verify_context (&ctx, image, error_list != NULL);
4116         ctx.stage = STAGE_TABLES;
4117
4118         verify_user_string (&ctx, offset);
4119
4120         return cleanup_context (&ctx, error_list);
4121 }
4122
4123 gboolean
4124 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4125 {
4126         VerifyContext ctx;
4127
4128         if (!mono_verifier_is_enabled_for_image (image))
4129                 return TRUE;
4130
4131         init_verify_context (&ctx, image, error_list != NULL);
4132         ctx.stage = STAGE_TABLES;
4133
4134         is_valid_cattr_blob (&ctx, offset);
4135
4136         return cleanup_context (&ctx, error_list);
4137 }
4138
4139 gboolean
4140 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4141 {
4142         VerifyContext ctx;
4143
4144         if (!mono_verifier_is_enabled_for_image (image))
4145                 return TRUE;
4146
4147         init_verify_context (&ctx, image, error_list != NULL);
4148         ctx.stage = STAGE_TABLES;
4149
4150         is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
4151
4152         return cleanup_context (&ctx, error_list);
4153 }
4154
4155 gboolean
4156 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4157 {
4158         MonoMethodSignature *original_sig;
4159         if (!mono_verifier_is_enabled_for_image (image))
4160                 return TRUE;
4161
4162         original_sig = mono_method_signature (method);
4163         if (original_sig->call_convention == MONO_CALL_VARARG) {
4164                 if (original_sig->hasthis != signature->hasthis)
4165                         return FALSE;
4166                 if (original_sig->call_convention != signature->call_convention)
4167                         return FALSE;
4168                 if (original_sig->explicit_this != signature->explicit_this)
4169                         return FALSE;
4170                 if (original_sig->call_convention != signature->call_convention)
4171                         return FALSE;
4172                 if (original_sig->pinvoke != signature->pinvoke)
4173                         return FALSE;
4174                 if (original_sig->sentinelpos != signature->sentinelpos)
4175                         return FALSE;
4176         } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4177                 return FALSE;
4178         }
4179
4180         return TRUE;
4181 }
4182
4183 gboolean
4184 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4185 {
4186         MonoTableInfo *table = &image->tables [MONO_TABLE_TYPEREF];
4187         guint32 data [MONO_TYPEREF_SIZE];
4188
4189         mono_error_init (error);
4190
4191         if (!mono_verifier_is_enabled_for_image (image))
4192                 return TRUE;
4193
4194         if (row >= table->rows) {
4195                 mono_error_set_bad_image (error, image, "Invalid typeref row %d - table has %d rows", row, table->rows);
4196                 return FALSE;
4197         }
4198
4199         mono_metadata_decode_row (table, row, data, MONO_TYPEREF_SIZE);
4200         if (!is_valid_coded_index_with_image (image, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4201                 mono_error_set_bad_image (error, image, "Invalid typeref row %d coded index 0x%08x", row, data [MONO_TYPEREF_SCOPE]);
4202                 return FALSE;
4203         }
4204
4205         if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4206                 mono_error_set_bad_image (error, image, "The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", row);
4207                 return FALSE;
4208         }
4209
4210         if (!data [MONO_TYPEREF_NAME] || !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAME], FALSE)) {
4211                 mono_error_set_bad_image (error, image, "Invalid typeref row %d name token 0x%08x", row, data [MONO_TYPEREF_NAME]);
4212                 return FALSE;
4213         }
4214
4215         if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAMESPACE], FALSE)) {
4216                 mono_error_set_bad_image (error, image, "Invalid typeref row %d namespace token 0x%08x", row, data [MONO_TYPEREF_NAMESPACE]);
4217                 return FALSE;
4218         }
4219
4220         return TRUE;
4221 }
4222
4223 /*Perform additional verification including metadata ones*/
4224 gboolean
4225 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4226 {
4227         MonoMethod *declaration, *body;
4228         MonoMethodSignature *body_sig, *decl_sig;
4229         MonoTableInfo *table = &image->tables [MONO_TABLE_METHODIMPL];
4230         guint32 data [MONO_METHODIMPL_SIZE];
4231
4232         mono_error_init (error);
4233
4234         if (!mono_verifier_is_enabled_for_image (image))
4235                 return TRUE;
4236
4237         if (row >= table->rows) {
4238                 mono_error_set_bad_image (error, image, "Invalid methodimpl row %d - table has %d rows", row, table->rows);
4239                 return FALSE;
4240         }
4241
4242         mono_metadata_decode_row (table, row, data, MONO_METHODIMPL_SIZE);
4243
4244         body = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_BODY], NULL);
4245         if (mono_loader_get_last_error ()) {
4246                 mono_loader_clear_error ();
4247                 mono_error_set_bad_image (error, image, "Invalid methodimpl body for row %x", row);
4248                 return FALSE;
4249         }
4250
4251         declaration = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_DECLARATION], NULL);
4252         if (mono_loader_get_last_error ()) {
4253                 mono_loader_clear_error ();
4254                 mono_error_set_bad_image (error, image, "Invalid methodimpl declaration for row %x", row);
4255                 return FALSE;
4256         }
4257
4258         /* FIXME
4259         mono_class_setup_supertypes (class);
4260         if (!mono_class_has_parent (class, body->klass)) {
4261                 mono_error_set_bad_image (error, image, "Invalid methodimpl body doesn't belong to parent for row %x", row);
4262                 return FALSE;
4263         }*/
4264
4265         if (!(body_sig = mono_method_signature_checked (body, error))) {
4266                 return FALSE;
4267         }
4268
4269         if (!(decl_sig = mono_method_signature_checked (declaration, error))) {
4270                 return FALSE;
4271         }
4272
4273         if (!mono_verifier_is_signature_compatible (decl_sig, body_sig)) {
4274                 mono_error_set_bad_image (error, image, "Invalid methodimpl body signature not compatible with declaration row %x", row);
4275                 return FALSE;
4276         }
4277
4278         return TRUE;
4279 }
4280
4281 #else
4282 gboolean
4283 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4284 {
4285         return TRUE;
4286 }
4287
4288 gboolean
4289 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
4290 {
4291         return TRUE;
4292 }
4293
4294 gboolean
4295 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
4296 {
4297         return TRUE;
4298 }
4299
4300 gboolean
4301 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4302 {
4303         return TRUE;
4304 }
4305
4306 gboolean
4307 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4308 {
4309         return TRUE;
4310 }
4311
4312 gboolean
4313 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4314 {
4315         return TRUE;
4316 }
4317
4318 gboolean
4319 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4320 {
4321         mono_error_init (error);
4322         return TRUE;
4323 }
4324
4325 gboolean
4326 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
4327 {
4328         return TRUE;
4329 }
4330
4331 gboolean
4332 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4333 {
4334         return TRUE;
4335 }
4336
4337 gboolean
4338 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4339 {
4340         return TRUE;
4341 }
4342
4343 gboolean
4344 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4345 {
4346         return TRUE;
4347 }
4348
4349 gboolean
4350 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4351 {
4352         return TRUE;
4353 }
4354
4355 gboolean
4356 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4357 {
4358         return TRUE;
4359 }
4360
4361 gboolean
4362 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4363 {
4364         return TRUE;
4365 }
4366
4367 gboolean
4368 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4369 {
4370         return TRUE;
4371 }
4372
4373
4374 gboolean
4375 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4376 {
4377         mono_error_init (error);
4378         return TRUE;
4379 }
4380
4381 gboolean
4382 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4383 {
4384         mono_error_init (error);
4385         return TRUE;
4386 }
4387
4388 #endif /* DISABLE_VERIFIER */