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
14void* 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
31static 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
51static 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
57static 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
102void make_leak(void)
103{
104   int* array2 __attribute__((unused)) = custom_alloc(sizeof(int) * 10);
105   array2 = 0;          // leak
106   return;
107}
108
109int 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