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