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