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