1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <unistd.h>
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "tests/sys_mman.h"
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <assert.h>
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdlib.h>
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "../memcheck.h"
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define SUPERBLOCK_SIZE    100000
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//-------------------------------------------------------------------------
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Allocator
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//-------------------------------------------------------------------------
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* get_superblock(void)
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   void* p = mmap( 0, SUPERBLOCK_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC,
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 );
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assert(p != ((void*)(-1)));
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Mark it no access;  although it's addressible we don't want the
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // program to be using it unless its handed out by custom_alloc()
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // with redzones, better not to have it
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VALGRIND_MAKE_MEM_NOACCESS(p, SUPERBLOCK_SIZE);
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return p;
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// has a redzone
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* custom_alloc(int size)
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define RZ  8
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static void* hp     = 0;    // current heap pointer
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static void* hp_lim = 0;    // maximum usable byte in current block
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   int          size2  = size + RZ*2;
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   void*        p;
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (hp + size2 > hp_lim) {
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hp = get_superblock();
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hp_lim = hp + SUPERBLOCK_SIZE - 1;
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p = hp + RZ;
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   hp += size2;
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VALGRIND_MALLOCLIKE_BLOCK( p, size, RZ, /*is_zeroed*/1 );
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (void*)p;
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void custom_free(void* p)
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // don't actually free any memory... but mark it as freed
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VALGRIND_FREELIKE_BLOCK( p, RZ );
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
56b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
57663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengstatic void checkredzone(void)
58663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng{
59663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* check that accessing the redzone of a MALLOCLIKE block
60663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      is detected  when the superblock was not marked as no access. */
61663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   char superblock[1 + RZ + 20 + RZ + 1];
62663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   char *p = 1 + RZ + superblock;
63663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   assert(RZ > 0);
64663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
65663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   // Indicate we have allocated p from our superblock:
66663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VALGRIND_MALLOCLIKE_BLOCK( p, 20, RZ, /*is_zeroed*/1 );
67663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[0] = 0;
68663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[-1] = p[0]; // error expected
69663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[-RZ] = p[0]; // error expected
70663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[-RZ-1] = p[0]; // no error expected
71663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
72663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[19] = 0;
73663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[19 + 1]  = p[0]; // error expected
74663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[19 + RZ] = p[0]; // error expected
75663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[19 + RZ + 1] = p[0]; // no error expected
76663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
77663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VALGRIND_FREELIKE_BLOCK( p, RZ );
78663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
79663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   // Now, indicate we have re-allocated p from our superblock
80663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   // but with only a size 10.
81663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VALGRIND_MALLOCLIKE_BLOCK( p, 10, RZ, /*is_zeroed*/1 );
82663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[0] = 0;
83663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[-1] = p[0]; // error expected
84663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[-RZ] = p[0]; // error expected
85663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[-RZ-1] = p[0]; // no error expected
86663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
87663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[9] = 0;
88663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[9 + 1]  = p[0]; // error expected
89663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[9 + RZ] = p[0]; // error expected
90663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   p[9 + RZ + 1] = p[0]; // no error expected
91663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
92663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VALGRIND_FREELIKE_BLOCK( p, RZ );
93663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
94663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng}
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//-------------------------------------------------------------------------
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Rest
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//-------------------------------------------------------------------------
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid make_leak(void)
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
104b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   int* array2 __attribute__((unused)) = custom_alloc(sizeof(int) * 10);
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   array2 = 0;          // leak
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return;
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main(void)
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   int *array, *array3;
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   int x;
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   array = custom_alloc(sizeof(int) * 10);
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   array[8]  = 8;
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   array[9]  = 8;
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   array[10] = 10;      // invalid write (ok w/o MALLOCLIKE -- in superblock)
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
119b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VALGRIND_RESIZEINPLACE_BLOCK(array, sizeof(int) * 10, sizeof(int) * 5, RZ);
120b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   array[4] = 7;
121b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   array[5] = 9; // invalid write
122b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
123b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // Make the entire array defined again such that it can be verified whether
124b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // the red zone is marked properly when resizing in place.
125b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VALGRIND_MAKE_MEM_DEFINED(array, sizeof(int) * 10);
126b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
127b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VALGRIND_RESIZEINPLACE_BLOCK(array, sizeof(int) * 5, sizeof(int) * 7, RZ);
128b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (array[5]) array[4]++; // uninitialized read of array[5]
129b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   array[5]  = 11;
130b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   array[6]  = 7;
131b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   array[7] = 8; // invalid write
132b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
133b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // invalid realloc
134b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VALGRIND_RESIZEINPLACE_BLOCK(array+1, sizeof(int) * 7, sizeof(int) * 8, RZ);
135b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   custom_free(array);  // ok
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   custom_free((void*)0x1);  // invalid free
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   array3 = malloc(sizeof(int) * 10);
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   custom_free(array3); // mismatched free (ok without MALLOCLIKE)
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   make_leak();
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x = array[0];        // use after free (ok without MALLOCLIKE/MAKE_MEM_NOACCESS)
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Bug 137073: passing 0 to MALLOCLIKE_BLOCK was causing an assertion
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // failure.  Test for this (and likewise for FREELIKE_BLOCK).
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VALGRIND_MALLOCLIKE_BLOCK(0,0,0,0);
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VALGRIND_FREELIKE_BLOCK(0,0);
150663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
151663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   checkredzone();
152663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return x;
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // leak from make_leak()
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
157b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
158b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#undef RZ
159