17e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include "../../config.h" 27e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 37e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#define _GNU_SOURCE 4a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes#include <inttypes.h> 57e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <stdio.h> 67e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <pthread.h> 77e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <string.h> 87e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <stdlib.h> 97e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <sys/types.h> 107e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <unistd.h> 117e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <assert.h> 127e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <setjmp.h> 137e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <signal.h> 147e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#ifdef HAVE_GETPAGESIZE 157e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <unistd.h> 167e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#endif 177e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include "../../include/valgrind.h" 187e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include "../memcheck.h" 197e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 207e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippetypedef unsigned long UWord; 217e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippetypedef UWord Addr; 227e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#define VG_ROUNDDN(p, a) ((Addr)(p) & ~((Addr)(a)-1)) 237e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#define VG_ROUNDUP(p, a) VG_ROUNDDN((p)+(a)-1, (a)) 247e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 257e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic pthread_t children; 267e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 277e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe// If != 0, will test addr description does not explode with 287e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe// wrong stack registration. 297e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic int shake_with_wrong_registration = 0; 307e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 317e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe/* Do whatever to have the stack grown enough that 327e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe we can access below sp relatively safely */ 337e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic void grow_the_stack(void) 347e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{ 357e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe int i; 367e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe char m[5000]; 377e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe for (i = 0; i < sizeof(m); i++) 387e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe m[i] = i; 397e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe sprintf(m, "do whatever %d", i); 407e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe if (strlen(m) > 1000) 417e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe fprintf(stderr, "something went wrong with %s\n", m); 427e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe} 437e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 447e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic char s[1000]; 457e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic void describe (char* what, void* a) 467e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{ 47a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes fprintf(stderr, "describing %#" PRIxPTR " %s\n", (uintptr_t) a, what); 48a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes sprintf(s, "v.info location %#" PRIxPTR, (uintptr_t) a); 497e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe VALGRIND_MONITOR_COMMAND(s); 507e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe} 517e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 527e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic void bad_things_below_sp (void) 537e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{ 547e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe int i; 557e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe char *p = (char*)&i; 567e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe describe ("1500 bytes below a local var", p-1500); 577e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe} 587e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 597e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 607e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic volatile char *lowest_j; 617e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic jmp_buf goback; 627e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 637e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic void sigsegv_handler(int signr) 647e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{ 657e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe longjmp(goback, 1); 667e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe} 677e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 687e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic void bad_things_till_guard_page(void) 697e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{ 707e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe char j = 0; 717e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe char *p = &j; 727e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 737e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe for (;;) { 747e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe j = j + *p; 757e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe p = p - 400; 767e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe lowest_j = p; 777e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe } 787e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe} 797e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 807e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic int guess_pagesize(void) 817e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{ 827e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#ifdef HAVE_GETPAGESIZE 837e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe const int pagesize = getpagesize(); 847e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#else 857e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe const int pagesize = 4096; // let's say ? 867e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#endif 877e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe return pagesize; 887e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe} 897e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 907e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic void describe_many(void) 917e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{ 927e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe const int pagesize = guess_pagesize(); 937e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe describe ("discovered address giving SEGV in thread stack", 947e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe (void*)lowest_j); 957e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe describe ("byte just above highest guardpage byte", 967e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe (void*) VG_ROUNDUP(lowest_j, pagesize)); 977e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe describe ("highest guardpage byte", 987e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe (void*) VG_ROUNDUP(lowest_j, pagesize)-1); 997e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe describe ("lowest guardpage byte", 1007e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe (void*) VG_ROUNDDN(lowest_j, pagesize)); 1017e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe /* Cannot test the next byte, as we cannot predict how 1027e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe this byte will be described. */ 1037e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe} 1047e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 1057e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic void* child_fn_0 ( void* arg ) 1067e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{ 1077e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe grow_the_stack(); 1087e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe bad_things_below_sp(); 1097e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 1107e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe if (setjmp(goback)) { 1117e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe describe_many(); 1127e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe } else 1137e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe bad_things_till_guard_page(); 1147e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 1157e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe if (shake_with_wrong_registration) { 1167e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe // Do whatever stupid things we could imagine 1177e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe // with stack registration and see no explosion happens 1187e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe // Note: this is executed only if an arg is given to the program. 1197e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe // 1207e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 1217e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe const int pgsz = guess_pagesize(); 1227e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe int stackid; 1237e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 1247e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe fprintf(stderr, "\n\nShaking after unregistering stack\n"); 1257e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe // Assuming our first stack was automatically registered as nr 1 1267e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe VALGRIND_STACK_DEREGISTER(1); 1277e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe // Test with no stack registered 1287e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe describe_many(); 1297e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 1307e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe fprintf(stderr, "\n\nShaking with small stack\n"); 1317e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe stackid = VALGRIND_STACK_REGISTER((void*) VG_ROUNDDN(&stackid, pgsz), 1327e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe (void*) VG_ROUNDUP(&stackid, pgsz)); 1337e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe describe_many(); 1347e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe VALGRIND_STACK_DEREGISTER(stackid); 1357e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 1367e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe fprintf(stderr, "\n\nShaking with huge stack\n"); 1377e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe stackid = VALGRIND_STACK_REGISTER((void*) 0x0, 1387e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe (void*) VG_ROUNDUP(&stackid, 2<<20)); 1397e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe describe_many(); 1407e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe VALGRIND_STACK_DEREGISTER(stackid); 1417e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 1427e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 1437e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe } 1447e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 1457e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe return NULL; 1467e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe} 1477e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 1487e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippeint main(int argc, const char** argv) 1497e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{ 1507e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe struct sigaction sa; 1517e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe int r; 1527e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 1537e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe shake_with_wrong_registration = argc > 1; 1547e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 1557e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe /* We will discover the thread guard page using SEGV. 1567e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe So, prepare an handler. */ 1577e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe sa.sa_handler = sigsegv_handler; 1587e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe sigemptyset(&sa.sa_mask); 1597e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe sa.sa_flags = 0; 1607e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 1617e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe if (sigaction (SIGSEGV, &sa, NULL) != 0) 1627e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe perror("sigaction"); 1637e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 1647e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe grow_the_stack(); 1657e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe bad_things_below_sp(); 166a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes 167a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes pthread_attr_t attrs; 168a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes r = pthread_attr_init(&attrs); 169a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes assert(!r); 170a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes 171a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes# if defined(VGO_solaris) 172a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes /* Solaris needs to configure at least two page sizes to have 173a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes a visible stack guard page. One page size is deducted for 174a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes an implicit mmap red zone. */ 175a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes r = pthread_attr_setguardsize(&attrs, 2 * guess_pagesize()); 1767e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe assert(!r); 177a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes# endif /* VGO_solaris */ 1787e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 179a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes r = pthread_create(&children, &attrs, child_fn_0, NULL); 180a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes assert(!r); 181a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes 182a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes r = pthread_attr_destroy(&attrs); 183a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes assert(!r); 184a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes 1857e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe r = pthread_join(children, NULL); 1867e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe assert(!r); 187a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes 188a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes 1897e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe return 0; 1907e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe} 1917e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 192