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   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
57
58
59
60//-------------------------------------------------------------------------
61// Rest
62//-------------------------------------------------------------------------
63
64void make_leak(void)
65{
66   int* array2 __attribute__((unused)) = custom_alloc(sizeof(int) * 10);
67   array2 = 0;          // leak
68   return;
69}
70
71int main(void)
72{
73   int *array, *array3;
74   int x;
75
76   array = custom_alloc(sizeof(int) * 10);
77   array[8]  = 8;
78   array[9]  = 8;
79   array[10] = 10;      // invalid write (ok w/o MALLOCLIKE -- in superblock)
80
81   VALGRIND_RESIZEINPLACE_BLOCK(array, sizeof(int) * 10, sizeof(int) * 5, RZ);
82   array[4] = 7;
83   array[5] = 9; // invalid write
84
85   // Make the entire array defined again such that it can be verified whether
86   // the red zone is marked properly when resizing in place.
87   VALGRIND_MAKE_MEM_DEFINED(array, sizeof(int) * 10);
88
89   VALGRIND_RESIZEINPLACE_BLOCK(array, sizeof(int) * 5, sizeof(int) * 7, RZ);
90   if (array[5]) array[4]++; // uninitialized read of array[5]
91   array[5]  = 11;
92   array[6]  = 7;
93   array[7] = 8; // invalid write
94
95   // invalid realloc
96   VALGRIND_RESIZEINPLACE_BLOCK(array+1, sizeof(int) * 7, sizeof(int) * 8, RZ);
97
98   custom_free(array);  // ok
99
100   custom_free((void*)0x1);  // invalid free
101
102   array3 = malloc(sizeof(int) * 10);
103   custom_free(array3); // mismatched free (ok without MALLOCLIKE)
104
105   make_leak();
106   x = array[0];        // use after free (ok without MALLOCLIKE/MAKE_MEM_NOACCESS)
107                        // (nb: initialised because is_zeroed==1 above)
108                        // unfortunately not identified as being in a free'd
109                        // block because the freeing of the block and shadow
110                        // chunk isn't postponed.
111
112   // Bug 137073: passing 0 to MALLOCLIKE_BLOCK was causing an assertion
113   // failure.  Test for this (and likewise for FREELIKE_BLOCK).
114   VALGRIND_MALLOCLIKE_BLOCK(0,0,0,0);
115   VALGRIND_FREELIKE_BLOCK(0,0);
116
117   return x;
118
119   // leak from make_leak()
120}
121
122#undef RZ
123