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 (void) 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
checkredzone(void)57 static void checkredzone(void)
58 {
59 /* check that accessing the redzone of a MALLOCLIKE block
60 is detected when the superblock was not marked as no access. */
61 char superblock[1 + RZ + 20 + RZ + 1];
62 char *p = 1 + RZ + superblock;
63 assert(RZ > 0);
64
65 // Indicate we have allocated p from our superblock:
66 VALGRIND_MALLOCLIKE_BLOCK( p, 20, RZ, /*is_zeroed*/1 );
67 p[0] = 0;
68 p[-1] = p[0]; // error expected
69 p[-RZ] = p[0]; // error expected
70 p[-RZ-1] = p[0]; // no error expected
71
72 p[19] = 0;
73 p[19 + 1] = p[0]; // error expected
74 p[19 + RZ] = p[0]; // error expected
75 p[19 + RZ + 1] = p[0]; // no error expected
76
77 VALGRIND_FREELIKE_BLOCK( p, RZ );
78
79 // Now, indicate we have re-allocated p from our superblock
80 // but with only a size 10.
81 VALGRIND_MALLOCLIKE_BLOCK( p, 10, RZ, /*is_zeroed*/1 );
82 p[0] = 0;
83 p[-1] = p[0]; // error expected
84 p[-RZ] = p[0]; // error expected
85 p[-RZ-1] = p[0]; // no error expected
86
87 p[9] = 0;
88 p[9 + 1] = p[0]; // error expected
89 p[9 + RZ] = p[0]; // error expected
90 p[9 + RZ + 1] = p[0]; // no error expected
91
92 VALGRIND_FREELIKE_BLOCK( p, RZ );
93
94 }
95
96
97
98 //-------------------------------------------------------------------------
99 // Rest
100 //-------------------------------------------------------------------------
101
make_leak(void)102 void make_leak(void)
103 {
104 int* array2 __attribute__((unused)) = custom_alloc(sizeof(int) * 10);
105 array2 = 0; // leak
106 return;
107 }
108
main(void)109 int main(void)
110 {
111 int *array, *array3;
112 int x;
113
114 array = custom_alloc(sizeof(int) * 10);
115 array[8] = 8;
116 array[9] = 8;
117 array[10] = 10; // invalid write (ok w/o MALLOCLIKE -- in superblock)
118
119 VALGRIND_RESIZEINPLACE_BLOCK(array, sizeof(int) * 10, sizeof(int) * 5, RZ);
120 array[4] = 7;
121 array[5] = 9; // invalid write
122
123 // Make the entire array defined again such that it can be verified whether
124 // the red zone is marked properly when resizing in place.
125 (void) VALGRIND_MAKE_MEM_DEFINED(array, sizeof(int) * 10);
126
127 VALGRIND_RESIZEINPLACE_BLOCK(array, sizeof(int) * 5, sizeof(int) * 7, RZ);
128 if (array[5]) array[4]++; // uninitialized read of array[5]
129 array[5] = 11;
130 array[6] = 7;
131 array[7] = 8; // invalid write
132
133 // invalid realloc
134 VALGRIND_RESIZEINPLACE_BLOCK(array+1, sizeof(int) * 7, sizeof(int) * 8, RZ);
135
136 custom_free(array); // ok
137
138 custom_free((void*)0x1); // invalid free
139
140 array3 = malloc(sizeof(int) * 10);
141 custom_free(array3); // mismatched free (ok without MALLOCLIKE)
142
143 make_leak();
144 x = array[0]; // use after free (ok without MALLOCLIKE/MAKE_MEM_NOACCESS)
145
146 // Bug 137073: passing 0 to MALLOCLIKE_BLOCK was causing an assertion
147 // failure. Test for this (and likewise for FREELIKE_BLOCK).
148 VALGRIND_MALLOCLIKE_BLOCK(0,0,0,0);
149 VALGRIND_FREELIKE_BLOCK(0,0);
150
151 checkredzone();
152
153 return x;
154
155 // leak from make_leak()
156 }
157
158 #undef RZ
159