File: descr_belowsp.c

package info (click to toggle)
valgrind 1%3A3.24.0-3
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 176,332 kB
  • sloc: ansic: 795,029; exp: 26,134; xml: 23,472; asm: 14,393; cpp: 9,397; makefile: 7,464; sh: 6,122; perl: 5,446; python: 1,498; javascript: 981; awk: 166; csh: 1
file content (191 lines) | stat: -rw-r--r-- 4,704 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#include "../../config.h"

#define _GNU_SOURCE
#include <inttypes.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include <setjmp.h>
#include <signal.h>
#ifdef HAVE_GETPAGESIZE
#include <unistd.h>
#endif
#include "../../include/valgrind.h"
#include "../memcheck.h"

typedef  unsigned long   UWord;
typedef  UWord           Addr;
#define VG_ROUNDDN(p, a)   ((Addr)(p) & ~((Addr)(a)-1))
#define VG_ROUNDUP(p, a)   VG_ROUNDDN((p)+(a)-1, (a))

static pthread_t children;

// If != 0, will test addr description does not explode with
// wrong stack registration.
static int shake_with_wrong_registration = 0;

/* Do whatever to have the stack grown enough that
   we can access below sp relatively safely */
static void grow_the_stack(void)
{
   int i;
   char m[5000];
   for (i = 0; i < sizeof(m); i++)
      m[i] = i;
   sprintf(m, "do whatever %d", i);
   if (strlen(m) > 1000)
      fprintf(stderr, "something went wrong with %s\n", m);
}

static char s[1000];
static void describe (char* what, void* a)
{
   fprintf(stderr, "describing %#" PRIxPTR " %s\n", (uintptr_t) a, what);
   sprintf(s, "v.info location %#" PRIxPTR, (uintptr_t) a);
   VALGRIND_MONITOR_COMMAND(s);
}

static void bad_things_below_sp (void)
{
   int i;
   char *p = (char*)&i;
   describe ("1500 bytes below a local var", p-1500);
}


static volatile char *lowest_j;
static jmp_buf goback;

static void sigsegv_handler(int signr)
{
   longjmp(goback, 1);
}

static void bad_things_till_guard_page(void)
{
   char j = 0;
   char *p = &j;

   for (;;) {
      j = j + *p;
      p = p - 400;
      lowest_j = p;
   }
}

static int guess_pagesize(void)
{
#ifdef HAVE_GETPAGESIZE
   const int pagesize = getpagesize();
#else
   const int pagesize = 4096; // let's say ?
#endif
   return pagesize;
}

static void describe_many(void)
{
   const int pagesize = guess_pagesize();
   describe ("discovered address giving SEGV in thread stack",
             (void*)lowest_j);
   describe ("byte just above highest guardpage byte",
             (void*) VG_ROUNDUP(lowest_j, pagesize));
   describe ("highest guardpage byte",
             (void*) VG_ROUNDUP(lowest_j, pagesize)-1);
   describe ("lowest guardpage byte",
             (void*) VG_ROUNDDN(lowest_j, pagesize));
   /* Cannot test the next byte, as we cannot predict how
      this byte will be described. */
}

static void* child_fn_0 ( void* arg )
{
   grow_the_stack();
   bad_things_below_sp();

   if (setjmp(goback)) {
      describe_many();
   } else
      bad_things_till_guard_page();

   if (shake_with_wrong_registration) {
      // Do whatever stupid things we could imagine
      // with stack registration and see no explosion happens
      // Note: this is executed only if an arg is given to the program.
      // 
      
      const int pgsz = guess_pagesize();
      int stackid;

      fprintf(stderr, "\n\nShaking after unregistering stack\n");
      // Assuming our first stack was automatically registered as nr 1
      VALGRIND_STACK_DEREGISTER(1);
      // Test with no stack registered
      describe_many();

      fprintf(stderr, "\n\nShaking with small stack\n");
      stackid = VALGRIND_STACK_REGISTER((void*) VG_ROUNDDN(&stackid, pgsz),
                                        (void*) VG_ROUNDUP(&stackid, pgsz));
      describe_many();
      VALGRIND_STACK_DEREGISTER(stackid);

      fprintf(stderr, "\n\nShaking with huge stack\n");
      stackid = VALGRIND_STACK_REGISTER((void*) 0x0,
                                        (void*) VG_ROUNDUP(&stackid, 2<<20));
      describe_many();
      VALGRIND_STACK_DEREGISTER(stackid);


   }

   return NULL;
}

int main(int argc, const char** argv)
{
   struct sigaction sa;
   int r;

   shake_with_wrong_registration = argc > 1;

   /* We will discover the thread guard page using SEGV.
      So, prepare an handler. */
   sa.sa_handler = sigsegv_handler;
   sigemptyset(&sa.sa_mask);
   sa.sa_flags = 0;

   if (sigaction (SIGSEGV, &sa, NULL) != 0)
      perror("sigaction");

   grow_the_stack();
   bad_things_below_sp();

   pthread_attr_t attrs;
   r = pthread_attr_init(&attrs);
   assert(!r);

#  if defined(VGO_solaris)
   /* Solaris needs to configure at least two page sizes to have
      a visible stack guard page. One page size is deducted for
      an implicit mmap red zone. */
   r = pthread_attr_setguardsize(&attrs, 2 * guess_pagesize());
   assert(!r);
#  endif /* VGO_solaris */
   
   r = pthread_create(&children, &attrs, child_fn_0, NULL);
   assert(!r);

   r = pthread_attr_destroy(&attrs);
   assert(!r);

   r = pthread_join(children, NULL);
   assert(!r);
 

   return 0;
}