1 #include <unistd.h>
2 #include "tests/sys_mman.h"
3 #include <assert.h>
4 #include <stdlib.h>
5
6 #include "../memcheck.h"
7
8 #define SUPERBLOCK_SIZE 100000
9
10 //-------------------------------------------------------------------------
11 // Allocator
12 //-------------------------------------------------------------------------
13
get_superblock(void)14 void* get_superblock(void)
15 {
16 void* p = mmap( 0, SUPERBLOCK_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC,
17 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 );
18
19 assert(p != ((void*)(-1)));
20
21 // Mark it no access; although it's addressible we don't want the
22 // program to be using it unless its handed out by custom_alloc()
23
24 // with redzones, better not to have it
25 VALGRIND_MAKE_MEM_NOACCESS(p, SUPERBLOCK_SIZE);
26
27 return p;
28 }
29
30 // has a redzone
custom_alloc(int size)31 static void* custom_alloc(int size)
32 {
33 #define RZ 8
34 static void* hp = 0; // current heap pointer
35 static void* hp_lim = 0; // maximum usable byte in current block
36 int size2 = size + RZ*2;
37 void* p;
38
39 if (hp + size2 > hp_lim) {
40 hp = get_superblock();
41 hp_lim = hp + SUPERBLOCK_SIZE - 1;
42 }
43
44 p = hp + RZ;
45 hp += size2;
46
47 VALGRIND_MALLOCLIKE_BLOCK( p, size, RZ, /*is_zeroed*/1 );
48 return (void*)p;
49 }
50
custom_free(void * p)51 static void custom_free(void* p)
52 {
53 // don't actually free any memory... but mark it as freed
54 VALGRIND_FREELIKE_BLOCK( p, RZ );
55 }
56
57
58
59
60 //-------------------------------------------------------------------------
61 // Rest
62 //-------------------------------------------------------------------------
63
make_leak(void)64 void make_leak(void)
65 {
66 int* array2 __attribute__((unused)) = custom_alloc(sizeof(int) * 10);
67 array2 = 0; // leak
68 return;
69 }
70
main(void)71 int main(void)
72 {
73 int *array, *array3;
74 int x;
75
76 array = custom_alloc(sizeof(int) * 10);
77 array[8] = 8;
78 array[9] = 8;
79 array[10] = 10; // invalid write (ok w/o MALLOCLIKE -- in superblock)
80
81 VALGRIND_RESIZEINPLACE_BLOCK(array, sizeof(int) * 10, sizeof(int) * 5, RZ);
82 array[4] = 7;
83 array[5] = 9; // invalid write
84
85 // Make the entire array defined again such that it can be verified whether
86 // the red zone is marked properly when resizing in place.
87 VALGRIND_MAKE_MEM_DEFINED(array, sizeof(int) * 10);
88
89 VALGRIND_RESIZEINPLACE_BLOCK(array, sizeof(int) * 5, sizeof(int) * 7, RZ);
90 if (array[5]) array[4]++; // uninitialized read of array[5]
91 array[5] = 11;
92 array[6] = 7;
93 array[7] = 8; // invalid write
94
95 // invalid realloc
96 VALGRIND_RESIZEINPLACE_BLOCK(array+1, sizeof(int) * 7, sizeof(int) * 8, RZ);
97
98 custom_free(array); // ok
99
100 custom_free((void*)0x1); // invalid free
101
102 array3 = malloc(sizeof(int) * 10);
103 custom_free(array3); // mismatched free (ok without MALLOCLIKE)
104
105 make_leak();
106 x = array[0]; // use after free (ok without MALLOCLIKE/MAKE_MEM_NOACCESS)
107 // (nb: initialised because is_zeroed==1 above)
108 // unfortunately not identified as being in a free'd
109 // block because the freeing of the block and shadow
110 // chunk isn't postponed.
111
112 // Bug 137073: passing 0 to MALLOCLIKE_BLOCK was causing an assertion
113 // failure. Test for this (and likewise for FREELIKE_BLOCK).
114 VALGRIND_MALLOCLIKE_BLOCK(0,0,0,0);
115 VALGRIND_FREELIKE_BLOCK(0,0);
116
117 return x;
118
119 // leak from make_leak()
120 }
121
122 #undef RZ
123