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