17e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include "../../config.h"
27e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
37e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#define _GNU_SOURCE
4a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes#include <inttypes.h>
57e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <stdio.h>
67e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <pthread.h>
77e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <string.h>
87e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <stdlib.h>
97e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <sys/types.h>
107e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <unistd.h>
117e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <assert.h>
127e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <setjmp.h>
137e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <signal.h>
147e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#ifdef HAVE_GETPAGESIZE
157e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include <unistd.h>
167e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#endif
177e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include "../../include/valgrind.h"
187e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#include "../memcheck.h"
197e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
207e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippetypedef  unsigned long   UWord;
217e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippetypedef  UWord           Addr;
227e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#define VG_ROUNDDN(p, a)   ((Addr)(p) & ~((Addr)(a)-1))
237e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#define VG_ROUNDUP(p, a)   VG_ROUNDDN((p)+(a)-1, (a))
247e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
257e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic pthread_t children;
267e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
277e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe// If != 0, will test addr description does not explode with
287e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe// wrong stack registration.
297e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic int shake_with_wrong_registration = 0;
307e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
317e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe/* Do whatever to have the stack grown enough that
327e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   we can access below sp relatively safely */
337e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic void grow_the_stack(void)
347e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{
357e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   int i;
367e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   char m[5000];
377e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   for (i = 0; i < sizeof(m); i++)
387e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      m[i] = i;
397e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   sprintf(m, "do whatever %d", i);
407e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   if (strlen(m) > 1000)
417e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      fprintf(stderr, "something went wrong with %s\n", m);
427e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe}
437e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
447e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic char s[1000];
457e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic void describe (char* what, void* a)
467e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{
47a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   fprintf(stderr, "describing %#" PRIxPTR " %s\n", (uintptr_t) a, what);
48a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   sprintf(s, "v.info location %#" PRIxPTR, (uintptr_t) a);
497e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   VALGRIND_MONITOR_COMMAND(s);
507e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe}
517e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
527e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic void bad_things_below_sp (void)
537e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{
547e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   int i;
557e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   char *p = (char*)&i;
567e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   describe ("1500 bytes below a local var", p-1500);
577e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe}
587e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
597e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
607e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic volatile char *lowest_j;
617e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic jmp_buf goback;
627e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
637e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic void sigsegv_handler(int signr)
647e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{
657e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   longjmp(goback, 1);
667e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe}
677e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
687e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic void bad_things_till_guard_page(void)
697e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{
707e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   char j = 0;
717e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   char *p = &j;
727e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
737e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   for (;;) {
747e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      j = j + *p;
757e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      p = p - 400;
767e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      lowest_j = p;
777e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   }
787e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe}
797e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
807e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic int guess_pagesize(void)
817e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{
827e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#ifdef HAVE_GETPAGESIZE
837e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   const int pagesize = getpagesize();
847e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#else
857e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   const int pagesize = 4096; // let's say ?
867e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe#endif
877e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   return pagesize;
887e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe}
897e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
907e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic void describe_many(void)
917e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{
927e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   const int pagesize = guess_pagesize();
937e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   describe ("discovered address giving SEGV in thread stack",
947e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe             (void*)lowest_j);
957e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   describe ("byte just above highest guardpage byte",
967e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe             (void*) VG_ROUNDUP(lowest_j, pagesize));
977e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   describe ("highest guardpage byte",
987e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe             (void*) VG_ROUNDUP(lowest_j, pagesize)-1);
997e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   describe ("lowest guardpage byte",
1007e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe             (void*) VG_ROUNDDN(lowest_j, pagesize));
1017e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   /* Cannot test the next byte, as we cannot predict how
1027e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      this byte will be described. */
1037e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe}
1047e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
1057e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippestatic void* child_fn_0 ( void* arg )
1067e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{
1077e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   grow_the_stack();
1087e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   bad_things_below_sp();
1097e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
1107e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   if (setjmp(goback)) {
1117e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      describe_many();
1127e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   } else
1137e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      bad_things_till_guard_page();
1147e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
1157e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   if (shake_with_wrong_registration) {
1167e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      // Do whatever stupid things we could imagine
1177e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      // with stack registration and see no explosion happens
1187e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      // Note: this is executed only if an arg is given to the program.
1197e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      //
1207e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
1217e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      const int pgsz = guess_pagesize();
1227e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      int stackid;
1237e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
1247e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      fprintf(stderr, "\n\nShaking after unregistering stack\n");
1257e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      // Assuming our first stack was automatically registered as nr 1
1267e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      VALGRIND_STACK_DEREGISTER(1);
1277e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      // Test with no stack registered
1287e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      describe_many();
1297e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
1307e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      fprintf(stderr, "\n\nShaking with small stack\n");
1317e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      stackid = VALGRIND_STACK_REGISTER((void*) VG_ROUNDDN(&stackid, pgsz),
1327e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe                                        (void*) VG_ROUNDUP(&stackid, pgsz));
1337e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      describe_many();
1347e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      VALGRIND_STACK_DEREGISTER(stackid);
1357e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
1367e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      fprintf(stderr, "\n\nShaking with huge stack\n");
1377e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      stackid = VALGRIND_STACK_REGISTER((void*) 0x0,
1387e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe                                        (void*) VG_ROUNDUP(&stackid, 2<<20));
1397e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      describe_many();
1407e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      VALGRIND_STACK_DEREGISTER(stackid);
1417e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
1427e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
1437e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   }
1447e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
1457e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   return NULL;
1467e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe}
1477e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
1487e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippeint main(int argc, const char** argv)
1497e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe{
1507e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   struct sigaction sa;
1517e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   int r;
1527e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
1537e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   shake_with_wrong_registration = argc > 1;
1547e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
1557e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   /* We will discover the thread guard page using SEGV.
1567e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      So, prepare an handler. */
1577e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   sa.sa_handler = sigsegv_handler;
1587e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   sigemptyset(&sa.sa_mask);
1597e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   sa.sa_flags = 0;
1607e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
1617e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   if (sigaction (SIGSEGV, &sa, NULL) != 0)
1627e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe      perror("sigaction");
1637e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
1647e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   grow_the_stack();
1657e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   bad_things_below_sp();
166a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes
167a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   pthread_attr_t attrs;
168a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   r = pthread_attr_init(&attrs);
169a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   assert(!r);
170a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes
171a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes#  if defined(VGO_solaris)
172a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   /* Solaris needs to configure at least two page sizes to have
173a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes      a visible stack guard page. One page size is deducted for
174a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes      an implicit mmap red zone. */
175a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   r = pthread_attr_setguardsize(&attrs, 2 * guess_pagesize());
1767e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   assert(!r);
177a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes#  endif /* VGO_solaris */
1787e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
179a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   r = pthread_create(&children, &attrs, child_fn_0, NULL);
180a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   assert(!r);
181a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes
182a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   r = pthread_attr_destroy(&attrs);
183a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   assert(!r);
184a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes
1857e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   r = pthread_join(children, NULL);
1867e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   assert(!r);
187a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes
188a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes
1897e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe   return 0;
1907e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe}
1917e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe
192