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