Home | History | Annotate | Download | only in tests
      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