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
|