File: custom_alloc.c

package info (click to toggle)
valgrind 1%3A3.19.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 170,080 kB
  • sloc: ansic: 782,981; exp: 26,134; xml: 22,780; asm: 14,072; cpp: 7,903; makefile: 6,768; perl: 6,097; sh: 5,669; javascript: 981; awk: 148
file content (158 lines) | stat: -rw-r--r-- 4,268 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <unistd.h>
#include "tests/sys_mman.h"
#include <assert.h>
#include <stdlib.h>

#include "../memcheck.h"

#define SUPERBLOCK_SIZE    100000

//-------------------------------------------------------------------------
// Allocator
//-------------------------------------------------------------------------

void* get_superblock(void)
{
   void* p = mmap( 0, SUPERBLOCK_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC,
                   MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 );

   assert(p != ((void*)(-1)));

   // Mark it no access;  although it's addressible we don't want the 
   // program to be using it unless its handed out by custom_alloc()

   // with redzones, better not to have it
   (void) VALGRIND_MAKE_MEM_NOACCESS(p, SUPERBLOCK_SIZE);

   return p;
}

// has a redzone
static void* custom_alloc(int size)
{
#define RZ  8
   static void* hp     = 0;    // current heap pointer
   static void* hp_lim = 0;    // maximum usable byte in current block
   int          size2  = size + RZ*2;
   void*        p;

   if (hp + size2 > hp_lim) {
      hp = get_superblock();
      hp_lim = hp + SUPERBLOCK_SIZE - 1;
   }  

   p = hp + RZ;
   hp += size2;

   VALGRIND_MALLOCLIKE_BLOCK( p, size, RZ, /*is_zeroed*/1 );
   return (void*)p;
}     

static void custom_free(void* p)
{
   // don't actually free any memory... but mark it as freed
   VALGRIND_FREELIKE_BLOCK( p, RZ );
}

static void checkredzone(void)
{
   /* check that accessing the redzone of a MALLOCLIKE block
      is detected  when the superblock was not marked as no access. */
   char superblock[1 + RZ + 20 + RZ + 1];
   char *p = 1 + RZ + superblock;
   assert(RZ > 0);

   // Indicate we have allocated p from our superblock:
   VALGRIND_MALLOCLIKE_BLOCK( p, 20, RZ, /*is_zeroed*/1 );
   p[0] = 0; 
   p[-1] = p[0]; // error expected
   p[-RZ] = p[0]; // error expected
   p[-RZ-1] = p[0]; // no error expected
   
   p[19] = 0; 
   p[19 + 1]  = p[0]; // error expected
   p[19 + RZ] = p[0]; // error expected
   p[19 + RZ + 1] = p[0]; // no error expected

   VALGRIND_FREELIKE_BLOCK( p, RZ );

   // Now, indicate we have re-allocated p from our superblock
   // but with only a size 10.
   VALGRIND_MALLOCLIKE_BLOCK( p, 10, RZ, /*is_zeroed*/1 );
   p[0] = 0; 
   p[-1] = p[0]; // error expected
   p[-RZ] = p[0]; // error expected
   p[-RZ-1] = p[0]; // no error expected
   
   p[9] = 0; 
   p[9 + 1]  = p[0]; // error expected
   p[9 + RZ] = p[0]; // error expected
   p[9 + RZ + 1] = p[0]; // no error expected

   VALGRIND_FREELIKE_BLOCK( p, RZ );

}



//-------------------------------------------------------------------------
// Rest
//-------------------------------------------------------------------------

void make_leak(void)
{
   int* array2 __attribute__((unused)) = custom_alloc(sizeof(int) * 10);
   array2 = 0;          // leak
   return;
}

int main(void)
{
   int *array, *array3;
   int x;

   array = custom_alloc(sizeof(int) * 10);
   array[8]  = 8;
   array[9]  = 8;
   array[10] = 10;      // invalid write (ok w/o MALLOCLIKE -- in superblock)

   VALGRIND_RESIZEINPLACE_BLOCK(array, sizeof(int) * 10, sizeof(int) * 5, RZ);
   array[4] = 7;
   array[5] = 9; // invalid write

   // Make the entire array defined again such that it can be verified whether
   // the red zone is marked properly when resizing in place.
   (void) VALGRIND_MAKE_MEM_DEFINED(array, sizeof(int) * 10);

   VALGRIND_RESIZEINPLACE_BLOCK(array, sizeof(int) * 5, sizeof(int) * 7, RZ);
   if (array[5]) array[4]++; // uninitialized read of array[5]
   array[5]  = 11;
   array[6]  = 7;
   array[7] = 8; // invalid write

   // invalid realloc
   VALGRIND_RESIZEINPLACE_BLOCK(array+1, sizeof(int) * 7, sizeof(int) * 8, RZ);

   custom_free(array);  // ok

   custom_free((void*)0x1);  // invalid free

   array3 = malloc(sizeof(int) * 10);
   custom_free(array3); // mismatched free (ok without MALLOCLIKE)

   make_leak();
   x = array[0];        // use after free (ok without MALLOCLIKE/MAKE_MEM_NOACCESS)

   // Bug 137073: passing 0 to MALLOCLIKE_BLOCK was causing an assertion
   // failure.  Test for this (and likewise for FREELIKE_BLOCK).
   VALGRIND_MALLOCLIKE_BLOCK(0,0,0,0);
   VALGRIND_FREELIKE_BLOCK(0,0);

   checkredzone();

   return x;

   // leak from make_leak()
}

#undef RZ