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