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