arm64 front end: add spec rules for {EQ,NE} after {LOGIC32,LOGIC64}.
[valgrind.git] / memcheck / tests / leak-autofreepool.c
blob3bd6e50dc36ab34054c6cbe67948274a075ef3c4
1 #include <time.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <assert.h>
5 #include <string.h>
6 #include <stdio.h>
8 #include "../memcheck.h"
10 // Test VALGRIND_CREATE_MEMPOOL_EXT features, the VALGRIND_MEMPOOL_METAPOOL and
11 // VALGRIND_MEMPOOL_AUTO_FREE flags.
12 // Also show that without these, having a custom allocator that:
13 // - Allocates a MEMPOOL
14 // - Uses ITSELF to get large blocks to populate the pool (so these are marked
15 // as MALLOCLIKE blocks)
16 // - Then passes out MALLOCLIKE blocks out of these pool blocks
17 // Was not previously supported by the 'loose model' for mempools in memcheck
18 // because it spotted these (correctly) as overlapping blocks (test case 3
19 // below).
20 // The VALGRIND_MEMPOOL_METAPOOL says not to treat these as overlaps.
22 // Also, when one of these metapool blocks is freed, memcheck will not auto-free
23 // the MALLOCLIKE blocks allocated from the meta-pool, and report them as leaks.
24 // When VALGRIND_MEMPOOL_AUTO_FREE is passed, no such leaks are reported.
25 // This is for custom allocators that destroy a pool without freeing the objects
26 // allocated from it, because that is the defined behaviour of the allocator.
28 struct pool
30 size_t allocated;
31 size_t used;
32 uint8_t *buf;
35 struct cell
37 struct cell *next;
38 char x[16 - sizeof(void*)];
41 static struct pool _PlainPool, *PlainPool = &_PlainPool;
42 static struct pool _MetaPool, *MetaPool = &_MetaPool;
44 #define N 10
45 #define POOL_BLOCK_SIZE 4096
46 #define NOISE_SIZE 256
48 // For easy testing, the plain mempool uses N allocations, the
49 // metapool 2 * N (so 10 reported leaks are from the plain pool, 20 must be
50 // from the metapool).
52 static int MetaPoolFlags = 0;
53 static int CleanupBeforeExit = 0;
54 static int GenerateNoise = 0;
55 static int NoiseCounter = 0;
57 static struct cell *cells_plain[2 * N];
58 static struct cell *cells_meta[2 * N];
60 static unsigned char *noise[3 * N];
62 static char PlainBlock[POOL_BLOCK_SIZE];
63 static char MetaBlock[POOL_BLOCK_SIZE];
65 void create_meta_pool (void)
67 VALGRIND_CREATE_MEMPOOL_EXT(MetaPool, 0, 0, MetaPoolFlags);
68 VALGRIND_MEMPOOL_ALLOC(MetaPool, MetaBlock, POOL_BLOCK_SIZE);
70 MetaPool->buf = (uint8_t *) MetaBlock;
71 MetaPool->allocated = POOL_BLOCK_SIZE;
72 MetaPool->used = 0;
74 /* A pool-block is expected to have metadata, and the core of
75 valgrind sees a MALLOCLIKE_BLOCK that starts at the same address
76 as a MEMPOOLBLOCK as a MEMPOOLBLOCK, hence never as a leak.
77 Introduce such some simulated metadata.
80 MetaPool->buf += sizeof(uint8_t);
81 MetaPool->used += sizeof(uint8_t);
84 static void create_plain_pool (void)
86 VALGRIND_CREATE_MEMPOOL(PlainPool, 0, 0);
88 PlainPool->buf = (uint8_t *) PlainBlock;
89 PlainPool->allocated = POOL_BLOCK_SIZE;
90 PlainPool->used = 0;
92 /* Same overhead */
93 PlainPool->buf += sizeof(uint8_t);
94 PlainPool->used += sizeof(uint8_t);
97 static void *allocate_meta_style (struct pool *p, size_t n)
99 void *a = p->buf + p->used;
100 assert(p->used + n < p->allocated);
102 // Simulate a custom allocator that allocates memory either directly for
103 // the application or for a custom memory pool: All are marked as MALLOCLIKE.
104 VALGRIND_MALLOCLIKE_BLOCK(a, n, 0, 0);
105 p->used += n;
107 return a;
110 static void *allocate_plain_style (struct pool *p, size_t n)
112 void *a = p->buf + p->used;
113 assert(p->used + n < p->allocated);
115 // And this is custom allocator that knows that it is allocating from a pool.
116 VALGRIND_MEMPOOL_ALLOC(p, a, n);
117 p->used += n;
119 return a;
122 /* flags */
124 static void set_flags ( int n )
126 switch (n) {
127 // Case 0: No special flags. VALGRIND_CREATE_MEMPOOL_EXT is same as
128 // VALGRIND_CREATE_MEMPOOL.
129 // When mempools are destroyed, the METAPOOL leaks because auto-free is
130 // missing. Must show 2*N (20) leaks.
131 // The VALGRIND_MEMPOOL_ALLOC items from the plain pool are automatically
132 // destroyed. CleanupBeforeExit means the metapool is freed and destroyed
133 // (simulating an app that cleans up before it exits), and when false it
134 // simply exits with the pool unaltered.
135 case 0:
136 MetaPoolFlags = 0;
137 CleanupBeforeExit = 1;
138 break;
140 // Case 1: VALGRIND_MEMPOOL_METAPOOL, no auto-free.
141 // Without explicit free, these MALLOCLIKE_BLOCK blocks are considered
142 // leaks. So this case should show same as case 0: 20 leaks.
143 case 1:
144 MetaPoolFlags = VALGRIND_MEMPOOL_METAPOOL;
145 CleanupBeforeExit = 1;
146 break;
148 // Same as before, but now the MALLOCLIKE blocks are auto-freed.
149 // Must show 0 leaks.
150 case 2:
151 MetaPoolFlags = VALGRIND_MEMPOOL_METAPOOL | VALGRIND_MEMPOOL_AUTO_FREE;
152 CleanupBeforeExit = 1;
153 break;
155 case 3: // Note: this is incorrect behaviour, and aborts valgrind.
156 // (so it is not exercised during regression testing).
157 // Just auto-free, not marked with meta pool flag.
158 // This is an error, and will cause valgrind to abort when the pool
159 // is created.
160 MetaPoolFlags = VALGRIND_MEMPOOL_AUTO_FREE;
161 CleanupBeforeExit = 1;
162 break;
164 case 4:
165 // No auto-free, no cleanup. Leaves overlapping blocks detected
166 // by valgrind, but those are ignored because of the METAPOOL.
167 // So, no crash, no problems, but 20 leaks.
168 MetaPoolFlags = VALGRIND_MEMPOOL_METAPOOL;
169 CleanupBeforeExit = 0;
170 break;
172 case 5:
173 // Main reason for the VALGRIND_MEMPOOL_METAPOOL flags: When not
174 // specified, and the application has a memorypool that has MALLOC_LIKE
175 // overlapping allocations, that leaves block(s) that overlap.
176 // Causes a fatal error.
177 // The METAPOOL allows the overlap. Test must show that without that
178 // flag, a fatal error occurs.
179 MetaPoolFlags = 0;
180 CleanupBeforeExit = 0;
181 break;
183 case 6:
184 // Test the VG_(HT_remove_at_Iter)() function, which removes a chunk
185 // from a hashlist without the need to reset the iterator. The pool
186 // is auto_freed, and the best test for the function (besides the ones
187 // already done above) is by allocating lots of other chunks that are
188 // NOT part of the pool so the MC_Alloc lists contain other stuff.
189 // That will make the iterator find stuff AND skip stuff.
190 MetaPoolFlags = VALGRIND_MEMPOOL_METAPOOL | VALGRIND_MEMPOOL_AUTO_FREE;
191 CleanupBeforeExit = 1;
192 GenerateNoise = 1;
193 break;
195 default:
196 assert(0);
200 static void GenerateNoisyBit (void)
202 // In case the HT_remove_at_Iter messes up the administration, the wrong
203 // blocks may be deleted from the list, making access to these noise-blocks
204 // invalid. So fill 256-byte blocks with easily tested contents.
206 noise[NoiseCounter] = malloc(NOISE_SIZE);
207 assert(noise[NoiseCounter] != NULL);
208 memset(noise[NoiseCounter],(unsigned char) (NoiseCounter % 256), NOISE_SIZE);
209 NoiseCounter++;
212 static void CheckNoiseContents (void)
214 int i;
216 for (i = 0; i < NoiseCounter; i++) {
217 unsigned char Check = (unsigned char) ( i % 256);
218 int j;
220 for (j = 0; j < NOISE_SIZE; j++) {
221 assert(noise[i][j] == Check);
226 int main( int argc, char** argv )
228 int arg;
229 size_t i;
231 assert(argc == 2 || argc == 3);
232 assert(argv[1]);
233 assert(strlen(argv[1]) == 1);
234 assert(argv[1][0] >= '0' && argv[1][0] <= '9');
235 arg = atoi( argv[1] );
236 set_flags( arg );
238 create_plain_pool();
239 create_meta_pool();
241 // N plain allocs
242 for (i = 0; i < N; ++i) {
243 cells_plain[i] = allocate_plain_style(PlainPool,sizeof(struct cell));
245 if (GenerateNoise)
246 GenerateNoisyBit();
249 // 2*N meta allocs
250 for (i = 0; i < 2 * N; ++i) {
251 cells_meta[i] = allocate_meta_style(MetaPool,sizeof(struct cell));
253 if (GenerateNoise)
254 GenerateNoisyBit();
257 // Leak the memory from the pools by losing the pointers.
258 for (i = 0; i < N; ++i) {
259 cells_plain[i] = NULL;
262 for (i = 0; i < 2 * N; ++i) {
263 cells_meta[i] = NULL;
266 if (GenerateNoise)
267 CheckNoiseContents();
269 // This must free MALLOCLIKE allocations from the pool when
270 // VALGRIND_MEMPOOL_AUTO_FREE
271 // is set for the pool and report leaks when not.
273 if (CleanupBeforeExit) {
274 VALGRIND_MEMPOOL_FREE(MetaPool, MetaBlock);
276 if (GenerateNoise)
277 CheckNoiseContents();
279 VALGRIND_DESTROY_MEMPOOL(MetaPool);
281 if (GenerateNoise)
282 CheckNoiseContents();
286 // Cleanup.
287 VALGRIND_DESTROY_MEMPOOL(PlainPool);
289 if (GenerateNoise)
290 CheckNoiseContents();
292 // Try to trigger an error in the bookkeeping by freeing the noise bits.
293 // Valgrind should report no leaks, and zero memory in use. If the
294 // new HT_remove_at_Iter function would corrupt the bookkeeping in any
295 // way, this should bring it out!
296 if (GenerateNoise) {
297 for (i = 0; i < NoiseCounter; i++)
298 free(noise[i]);
302 // Perf test
303 if (argc == 3) {
304 struct pool perf_plain_pool;
305 void *perf_plain_block;
306 struct pool perf_meta_pool;
307 void *perf_meta_block;
308 size_t pool_block_size;
309 int n;
310 int nr_elts = atoi( argv[2] );
311 time_t dnow;
312 #define tprintf(...) (dnow = time(NULL), \
313 printf(__VA_ARGS__), \
314 printf(" %s", ctime(&dnow)))
316 pool_block_size = nr_elts * sizeof(struct cell) + sizeof(uint8_t) + 1;
318 // Create perf meta pool
319 VALGRIND_CREATE_MEMPOOL_EXT
320 (&perf_meta_pool, 0, 0,
321 VALGRIND_MEMPOOL_METAPOOL | VALGRIND_MEMPOOL_AUTO_FREE);
322 perf_meta_block = malloc(pool_block_size);
324 VALGRIND_MEMPOOL_ALLOC(&perf_meta_pool, perf_meta_block,
325 pool_block_size);
327 perf_meta_pool.buf = (uint8_t *) perf_meta_block;
328 perf_meta_pool.allocated = pool_block_size;
329 perf_meta_pool.used = 0;
332 perf_meta_pool.buf += sizeof(uint8_t);
333 perf_meta_pool.used += sizeof(uint8_t);
335 // Create perf plain pool
336 VALGRIND_CREATE_MEMPOOL(&perf_plain_pool, 0, 0);
337 perf_plain_block = malloc(pool_block_size);
339 perf_plain_pool.buf = (uint8_t *) perf_plain_block;
340 perf_plain_pool.allocated = pool_block_size;;
341 perf_plain_pool.used = 0;
343 perf_plain_pool.buf += sizeof(uint8_t);
344 perf_plain_pool.used += sizeof(uint8_t);
346 tprintf("allocating %d elts", nr_elts);
347 for (n = 0; n < nr_elts; n++) {
348 (void) allocate_meta_style (&perf_meta_pool, sizeof(struct cell));
349 (void) allocate_plain_style (&perf_plain_pool, sizeof(struct cell));
352 tprintf("freeing mempool");
353 VALGRIND_MEMPOOL_FREE(&perf_meta_pool, perf_meta_block);
354 tprintf("destroying mempool");
355 VALGRIND_DESTROY_MEMPOOL(&perf_meta_pool);
356 tprintf("done");
359 return 0;