1b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// Simplified version of mempool.c, that is more oriented towards
3b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// checking that the description of invalid addresses is correct.
4b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
5b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <stdio.h>
6b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <unistd.h>
7b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include "tests/sys_mman.h"
8b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <assert.h>
9b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <stdlib.h>
10b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
11b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include "../memcheck.h"
12b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
13b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#define SUPERBLOCK_SIZE 100000
14b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#define REDZONE_SIZE 8
15b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
16b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovtypedef struct _level_list
17b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
18b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   struct _level_list *next;
19b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   char *where;
20b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // Padding ensures the struct is the same size on 32-bit and 64-bit
21b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // machines.
22b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   char padding[16 - 2*sizeof(char*)];
23b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov} level_list;
24b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
25b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovtypedef struct _pool {
26b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   char *mem;
27b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   char *where;
28b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   level_list *levels;
29b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   int size, left;
30b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // Padding ensures the struct is the same size on 32-bit and 64-bit
31b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // machines.
32b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   char padding[24 - 3*sizeof(char*)];
33b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov} pool;
34b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
35b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovpool *make_pool( int use_mmap )
36b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
37b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   pool *p;
38b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
39b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (use_mmap) {
40b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      p = (pool *)mmap(0, sizeof(pool), PROT_READ|PROT_WRITE|PROT_EXEC,
41b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                       MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
42b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      p->where = p->mem = (char *)mmap(NULL, SUPERBLOCK_SIZE,
43b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                       PROT_READ|PROT_WRITE|PROT_EXEC,
44b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                       MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
45b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
46b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      p = (pool *)malloc(sizeof(pool));
47b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      p->where = p->mem = (char *)malloc(SUPERBLOCK_SIZE);
48b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
49b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
50b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   p->size = p->left = SUPERBLOCK_SIZE;
51b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   p->levels = NULL;
52b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VALGRIND_MAKE_MEM_NOACCESS(p->where, SUPERBLOCK_SIZE);
53b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return p;
54b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
55b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
56b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid push(pool *p, int use_mmap )
57b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
58b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   level_list *l;
59b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
60b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (use_mmap)
61b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      l = (level_list *)mmap(0, sizeof(level_list),
62b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                             PROT_READ|PROT_WRITE|PROT_EXEC,
63b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                             MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
64b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   else
65b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      l = (level_list *)malloc(sizeof(level_list));
66b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
67b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   l->next = p->levels;
68b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   l->where = p->where;
69b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VALGRIND_CREATE_MEMPOOL(l->where, REDZONE_SIZE, 0);
70b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   p->levels = l;
71b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
72b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
73b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid pop(pool *p, int use_mmap)
74b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
75b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   level_list *l = p->levels;
76b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   p->levels = l->next;
77b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VALGRIND_DESTROY_MEMPOOL(l->where);
78b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VALGRIND_MAKE_MEM_NOACCESS(l->where, p->where-l->where);
79b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   p->where = l->where;
80b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (use_mmap)
81b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      munmap(l, sizeof(level_list));
82b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   else
83b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      free(l);
84b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
85b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
86b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid destroy_pool(pool *p, int use_mmap)
87b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
88b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   level_list *l = p->levels;
89b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
90b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   while(l) {
91b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      pop(p, use_mmap);
92b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
93b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (use_mmap) {
94b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      munmap(p->mem, SUPERBLOCK_SIZE);
95b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      munmap(p, sizeof(pool));
96b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
97b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      free(p->mem);
98b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      free(p);
99b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
100b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
101b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
102b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovchar *allocate(pool *p, int size)
103b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
104b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   char *where;
105b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   p->left -= size + (REDZONE_SIZE*2);
106b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   where = p->where + REDZONE_SIZE;
107b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   p->where += size + (REDZONE_SIZE*2);
108b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VALGRIND_MEMPOOL_ALLOC(p->levels->where, where, size);
109b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return where;
110b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
111b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
112b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//-------------------------------------------------------------------------
113b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// Rest
114b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov//-------------------------------------------------------------------------
115b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
116b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid test(void)
117b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
118b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   char *x1, *x2;
119b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   char res = 0;
120b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
121b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // p1 is a malloc-backed pool
122b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   pool *p1 = make_pool(0);
123b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
124b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // p2 is a mmap-backed pool
125b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   pool *p2 = make_pool(1);
126b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
127b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   push(p1, 0);
128b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   push(p2, 1);
129b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
130b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   x1 = allocate(p1, 10);
131b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   x2 = allocate(p2, 20);
132b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
133b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   fprintf(stderr,
134b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           "\n------ out of range reads in malloc-backed pool ------\n\n");
135b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   res += x1[-1];
136b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   res += x1[10];
137b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
138b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   fprintf(stderr,
139b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           "\n------ out of range reads in mmap-backed pool ------\n\n");
140b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   res += x2[-1]; // invalid
141b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   res += x2[20]; // invalid
142b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
143b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   fprintf(stderr,
144b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           "\n------ read free in malloc-backed pool ------\n\n");
145b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VALGRIND_MEMPOOL_FREE(p1, x1);
146b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   res += x1[5];
147b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
148b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   fprintf(stderr,
149b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           "\n------ read free in mmap-backed pool ------\n\n");
150b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VALGRIND_MEMPOOL_FREE(p2, x2);
151b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   res += x2[11];
152b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
153b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   fprintf(stderr,
154b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           "\n------ double free in malloc-backed pool ------\n\n");
155b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VALGRIND_MEMPOOL_FREE(p1, x1);
156b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
157b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   fprintf(stderr,
158b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           "\n------ double free in mmap-backed pool ------\n\n");
159b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VALGRIND_MEMPOOL_FREE(p2, x2);
160b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
161663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   {
162663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      // test that redzone are still protected even if the user forgets
163663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      // to mark the superblock noaccess.
164663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      char superblock[100];
165663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
166663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      VALGRIND_CREATE_MEMPOOL(superblock, REDZONE_SIZE, 0);
167663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      // User should mark the superblock no access to benefit
168663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      // from full Valgrind memcheck protection.
169663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      // VALGRIND_MEMPOOL_ALLOC will however still ensure the
170663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      // redzones are protected.
171663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      VALGRIND_MEMPOOL_ALLOC(superblock, superblock+30, 10);
172663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
173663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      res += superblock[30]; // valid
174663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      res += superblock[39]; // valid
175663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
176663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      fprintf(stderr,
177663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng              "\n------ 2 invalid access in 'no no-access superblock' ---\n\n");
178663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      res += superblock[29]; // invalid
179663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      res += superblock[40]; // invalid
180663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
181663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      VALGRIND_DESTROY_MEMPOOL(superblock);
182663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
183b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // claim res is used, so gcc can't nuke this all
184b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   __asm__ __volatile__("" : : "r"(res));
185b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
186b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   fprintf(stderr,
187b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           "\n------ done ------\n\n");
188b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   pop(p1, 0);
189b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   pop(p2, 1);
190b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   destroy_pool(p1, 0);
191b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   destroy_pool(p2, 1);
192b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
193b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
194b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovint main(void)
195b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
196b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   test();
197b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return 0;
198b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
199