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