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 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
#include "../../config.h"
#define _GNU_SOURCE
#include <inttypes.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include <setjmp.h>
#include <signal.h>
#ifdef HAVE_GETPAGESIZE
#include <unistd.h>
#endif
#include "../../include/valgrind.h"
#include "../memcheck.h"
typedef unsigned long UWord;
typedef UWord Addr;
#define VG_ROUNDDN(p, a) ((Addr)(p) & ~((Addr)(a)-1))
#define VG_ROUNDUP(p, a) VG_ROUNDDN((p)+(a)-1, (a))
static pthread_t children;
// If != 0, will test addr description does not explode with
// wrong stack registration.
static int shake_with_wrong_registration = 0;
/* Do whatever to have the stack grown enough that
we can access below sp relatively safely */
static void grow_the_stack(void)
{
int i;
char m[5000];
for (i = 0; i < sizeof(m); i++)
m[i] = i;
sprintf(m, "do whatever %d", i);
if (strlen(m) > 1000)
fprintf(stderr, "something went wrong with %s\n", m);
}
static char s[1000];
static void describe (char* what, void* a)
{
fprintf(stderr, "describing %#" PRIxPTR " %s\n", (uintptr_t) a, what);
sprintf(s, "v.info location %#" PRIxPTR, (uintptr_t) a);
VALGRIND_MONITOR_COMMAND(s);
}
static void bad_things_below_sp (void)
{
int i;
char *p = (char*)&i;
describe ("1500 bytes below a local var", p-1500);
}
static volatile char *lowest_j;
static jmp_buf goback;
static void sigsegv_handler(int signr)
{
longjmp(goback, 1);
}
static void bad_things_till_guard_page(void)
{
char j = 0;
char *p = &j;
for (;;) {
j = j + *p;
p = p - 400;
lowest_j = p;
}
}
static int guess_pagesize(void)
{
#ifdef HAVE_GETPAGESIZE
const int pagesize = getpagesize();
#else
const int pagesize = 4096; // let's say ?
#endif
return pagesize;
}
static void describe_many(void)
{
const int pagesize = guess_pagesize();
describe ("discovered address giving SEGV in thread stack",
(void*)lowest_j);
describe ("byte just above highest guardpage byte",
(void*) VG_ROUNDUP(lowest_j, pagesize));
describe ("highest guardpage byte",
(void*) VG_ROUNDUP(lowest_j, pagesize)-1);
describe ("lowest guardpage byte",
(void*) VG_ROUNDDN(lowest_j, pagesize));
/* Cannot test the next byte, as we cannot predict how
this byte will be described. */
}
static void* child_fn_0 ( void* arg )
{
grow_the_stack();
bad_things_below_sp();
if (setjmp(goback)) {
describe_many();
} else
bad_things_till_guard_page();
if (shake_with_wrong_registration) {
// Do whatever stupid things we could imagine
// with stack registration and see no explosion happens
// Note: this is executed only if an arg is given to the program.
//
const int pgsz = guess_pagesize();
int stackid;
fprintf(stderr, "\n\nShaking after unregistering stack\n");
// Assuming our first stack was automatically registered as nr 1
VALGRIND_STACK_DEREGISTER(1);
// Test with no stack registered
describe_many();
fprintf(stderr, "\n\nShaking with small stack\n");
stackid = VALGRIND_STACK_REGISTER((void*) VG_ROUNDDN(&stackid, pgsz),
(void*) VG_ROUNDUP(&stackid, pgsz));
describe_many();
VALGRIND_STACK_DEREGISTER(stackid);
fprintf(stderr, "\n\nShaking with huge stack\n");
stackid = VALGRIND_STACK_REGISTER((void*) 0x0,
(void*) VG_ROUNDUP(&stackid, 2<<20));
describe_many();
VALGRIND_STACK_DEREGISTER(stackid);
}
return NULL;
}
int main(int argc, const char** argv)
{
struct sigaction sa;
int r;
shake_with_wrong_registration = argc > 1;
/* We will discover the thread guard page using SEGV.
So, prepare an handler. */
sa.sa_handler = sigsegv_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction (SIGSEGV, &sa, NULL) != 0)
perror("sigaction");
grow_the_stack();
bad_things_below_sp();
pthread_attr_t attrs;
r = pthread_attr_init(&attrs);
assert(!r);
# if defined(VGO_solaris)
/* Solaris needs to configure at least two page sizes to have
a visible stack guard page. One page size is deducted for
an implicit mmap red zone. */
r = pthread_attr_setguardsize(&attrs, 2 * guess_pagesize());
assert(!r);
# endif /* VGO_solaris */
r = pthread_create(&children, &attrs, child_fn_0, NULL);
assert(!r);
r = pthread_attr_destroy(&attrs);
assert(!r);
r = pthread_join(children, NULL);
assert(!r);
return 0;
}
|