Home | History | Annotate | Download | only in tests
      1 #include "../../config.h"
      2 
      3 #define _GNU_SOURCE
      4 #include <stdio.h>
      5 #include <pthread.h>
      6 #include <string.h>
      7 #include <stdlib.h>
      8 #include <sys/types.h>
      9 #include <unistd.h>
     10 #include <assert.h>
     11 #include <setjmp.h>
     12 #include <signal.h>
     13 #ifdef HAVE_GETPAGESIZE
     14 #include <unistd.h>
     15 #endif
     16 #include "../../include/valgrind.h"
     17 #include "../memcheck.h"
     18 
     19 typedef  unsigned long   UWord;
     20 typedef  UWord           Addr;
     21 #define VG_ROUNDDN(p, a)   ((Addr)(p) & ~((Addr)(a)-1))
     22 #define VG_ROUNDUP(p, a)   VG_ROUNDDN((p)+(a)-1, (a))
     23 
     24 static pthread_t children;
     25 
     26 // If != 0, will test addr description does not explode with
     27 // wrong stack registration.
     28 static int shake_with_wrong_registration = 0;
     29 
     30 /* Do whatever to have the stack grown enough that
     31    we can access below sp relatively safely */
     32 static void grow_the_stack(void)
     33 {
     34    int i;
     35    char m[5000];
     36    for (i = 0; i < sizeof(m); i++)
     37       m[i] = i;
     38    sprintf(m, "do whatever %d", i);
     39    if (strlen(m) > 1000)
     40       fprintf(stderr, "something went wrong with %s\n", m);
     41 }
     42 
     43 static char s[1000];
     44 static void describe (char* what, void* a)
     45 {
     46    fprintf(stderr, "describing %p %s\n", a, what);
     47    sprintf(s, "v.info location %p", a);
     48    VALGRIND_MONITOR_COMMAND(s);
     49 }
     50 
     51 static void bad_things_below_sp (void)
     52 {
     53    int i;
     54    char *p = (char*)&i;
     55    describe ("1500 bytes below a local var", p-1500);
     56 }
     57 
     58 
     59 static volatile char *lowest_j;
     60 static jmp_buf goback;
     61 
     62 static void sigsegv_handler(int signr)
     63 {
     64    longjmp(goback, 1);
     65 }
     66 
     67 static void bad_things_till_guard_page(void)
     68 {
     69    char j = 0;
     70    char *p = &j;
     71 
     72    for (;;) {
     73       j = j + *p;
     74       p = p - 400;
     75       lowest_j = p;
     76    }
     77 }
     78 
     79 static int guess_pagesize(void)
     80 {
     81 #ifdef HAVE_GETPAGESIZE
     82    const int pagesize = getpagesize();
     83 #else
     84    const int pagesize = 4096; // let's say ?
     85 #endif
     86    return pagesize;
     87 }
     88 
     89 static void describe_many(void)
     90 {
     91    const int pagesize = guess_pagesize();
     92    describe ("discovered address giving SEGV in thread stack",
     93              (void*)lowest_j);
     94    describe ("byte just above highest guardpage byte",
     95              (void*) VG_ROUNDUP(lowest_j, pagesize));
     96    describe ("highest guardpage byte",
     97              (void*) VG_ROUNDUP(lowest_j, pagesize)-1);
     98    describe ("lowest guardpage byte",
     99              (void*) VG_ROUNDDN(lowest_j, pagesize));
    100    /* Cannot test the next byte, as we cannot predict how
    101       this byte will be described. */
    102 }
    103 
    104 static void* child_fn_0 ( void* arg )
    105 {
    106    grow_the_stack();
    107    bad_things_below_sp();
    108 
    109    if (setjmp(goback)) {
    110       describe_many();
    111    } else
    112       bad_things_till_guard_page();
    113 
    114    if (shake_with_wrong_registration) {
    115       // Do whatever stupid things we could imagine
    116       // with stack registration and see no explosion happens
    117       // Note: this is executed only if an arg is given to the program.
    118       //
    119 
    120       const int pgsz = guess_pagesize();
    121       int stackid;
    122 
    123       fprintf(stderr, "\n\nShaking after unregistering stack\n");
    124       // Assuming our first stack was automatically registered as nr 1
    125       VALGRIND_STACK_DEREGISTER(1);
    126       // Test with no stack registered
    127       describe_many();
    128 
    129       fprintf(stderr, "\n\nShaking with small stack\n");
    130       stackid = VALGRIND_STACK_REGISTER((void*) VG_ROUNDDN(&stackid, pgsz),
    131                                         (void*) VG_ROUNDUP(&stackid, pgsz));
    132       describe_many();
    133       VALGRIND_STACK_DEREGISTER(stackid);
    134 
    135       fprintf(stderr, "\n\nShaking with huge stack\n");
    136       stackid = VALGRIND_STACK_REGISTER((void*) 0x0,
    137                                         (void*) VG_ROUNDUP(&stackid, 2<<20));
    138       describe_many();
    139       VALGRIND_STACK_DEREGISTER(stackid);
    140 
    141 
    142    }
    143 
    144    return NULL;
    145 }
    146 
    147 int main(int argc, const char** argv)
    148 {
    149    struct sigaction sa;
    150    int r;
    151 
    152    shake_with_wrong_registration = argc > 1;
    153 
    154    /* We will discover the thread guard page using SEGV.
    155       So, prepare an handler. */
    156    sa.sa_handler = sigsegv_handler;
    157    sigemptyset(&sa.sa_mask);
    158    sa.sa_flags = 0;
    159 
    160    if (sigaction (SIGSEGV, &sa, NULL) != 0)
    161       perror("sigaction");
    162 
    163    grow_the_stack();
    164    bad_things_below_sp();
    165 
    166    r = pthread_create(&children, NULL, child_fn_0, NULL);
    167    assert(!r);
    168 
    169    r = pthread_join(children, NULL);
    170    assert(!r);
    171 
    172 
    173    return 0;
    174 }
    175 
    176