njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 1 | #include <unistd.h> |
| 2 | #include <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, |
mueller | 535cc6e | 2004-01-03 14:18:02 +0000 | [diff] [blame] | 17 | MAP_PRIVATE|MAP_ANON, -1, 0 ); |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 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_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 | #undef RZ |
| 57 | |
| 58 | |
| 59 | |
| 60 | //------------------------------------------------------------------------- |
| 61 | // Rest |
| 62 | //------------------------------------------------------------------------- |
| 63 | |
| 64 | void make_leak(void) |
| 65 | { |
| 66 | int* array2 = custom_alloc(sizeof(int) * 10); |
| 67 | array2 = 0; // leak |
| 68 | return; |
| 69 | } |
| 70 | |
| 71 | int main(void) |
| 72 | { |
| 73 | int* array; |
| 74 | int* array3; |
| 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 | custom_free(array); // ok |
| 82 | |
| 83 | custom_free(NULL); // invalid free (ok without MALLOCLIKE) |
| 84 | |
| 85 | array3 = malloc(sizeof(int) * 10); |
| 86 | custom_free(array3); // mismatched free (ok without MALLOCLIKE) |
| 87 | |
| 88 | make_leak(); |
| 89 | return array[0]; // use after free (ok without MALLOCLIKE/MAKE_NOACCESS) |
| 90 | // (nb: initialised because is_zeroed==1 above) |
| 91 | // unfortunately not identified as being in a free'd |
| 92 | // block because the freeing of the block and shadow |
| 93 | // chunk isn't postponed. |
| 94 | |
| 95 | // leak from make_leak() |
| 96 | } |