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 */
grow_the_stack(void)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];
describe(char * what,void * a)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
bad_things_below_sp(void)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
sigsegv_handler(int signr)63 static void sigsegv_handler(int signr)
64 {
65 longjmp(goback, 1);
66 }
67
bad_things_till_guard_page(void)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
guess_pagesize(void)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
describe_many(void)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
child_fn_0(void * arg)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
main(int argc,const char ** argv)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