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