libsigsegv  2.10
About: libsigsegv is a library for handling memory page faults in user mode.
  Fossies Dox: libsigsegv-2.10.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

 All Data Structures Files Functions Variables Typedefs Macros
stackoverflow2.c
Go to the documentation of this file.
1 /* Test that stack overflow and SIGSEGV are correctly distinguished.
2  Copyright (C) 2002-2006, 2008 Bruno Haible <bruno@clisp.org>
3  Copyright (C) 2010 Eric Blake <eblake@redhat.com>
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2, or (at your option)
8  any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software Foundation,
17  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 
19 #ifndef _MSC_VER
20 # include <config.h>
21 #endif
22 
23 #include "sigsegv.h"
24 #include <stdio.h>
25 #include <limits.h>
26 
27 #if HAVE_STACK_OVERFLOW_RECOVERY && HAVE_SIGSEGV_RECOVERY
28 
29 #if defined _WIN32 && !defined __CYGWIN__
30  /* Windows doesn't have sigset_t. */
31  typedef int sigset_t;
32 # define sigemptyset(set)
33 # define sigprocmask(how,set,oldset)
34 #endif
35 
36 #include "mmaputil.h"
37 #include <stddef.h> /* needed for NULL on SunOS4 */
38 #include <stdlib.h> /* for abort, exit */
39 #include <signal.h>
40 #include <setjmp.h>
41 #if HAVE_SETRLIMIT
42 # include <sys/types.h>
43 # include <sys/time.h>
44 # include <sys/resource.h>
45 #endif
46 #include "altstack.h"
47 
48 jmp_buf mainloop;
49 sigset_t mainsigset;
50 
51 volatile int pass = 0;
52 unsigned long page;
53 
54 static void
55 stackoverflow_handler_continuation (void *arg1, void *arg2, void *arg3)
56 {
57  int arg = (int) (long) arg1;
58  longjmp (mainloop, arg);
59 }
60 
61 void
62 stackoverflow_handler (int emergency, stackoverflow_context_t scp)
63 {
64  pass++;
65  if (pass <= 2)
66  printf ("Stack overflow %d caught.\n", pass);
67  else
68  {
69  printf ("Segmentation violation misdetected as stack overflow.\n");
70  exit (1);
71  }
72  sigprocmask (SIG_SETMASK, &mainsigset, NULL);
73  sigsegv_leave_handler (stackoverflow_handler_continuation,
74  (void *) (long) (emergency ? -1 : pass), NULL, NULL);
75 }
76 
77 int
78 sigsegv_handler (void *address, int emergency)
79 {
80  /* This test is necessary to distinguish stack overflow and SIGSEGV. */
81  if (!emergency)
82  return 0;
83 
84  pass++;
85  if (pass <= 2)
86  {
87  printf ("Stack overflow %d missed.\n", pass);
88  exit (1);
89  }
90  else
91  printf ("Segmentation violation correctly detected.\n");
92  sigprocmask (SIG_SETMASK, &mainsigset, NULL);
93  return sigsegv_leave_handler (stackoverflow_handler_continuation,
94  (void *) (long) pass, NULL, NULL);
95 }
96 
97 volatile int *
98 recurse_1 (int n, volatile int *p)
99 {
100  if (n < INT_MAX)
101  *recurse_1 (n + 1, p) += n;
102  return p;
103 }
104 
105 int
106 recurse (volatile int n)
107 {
108  return *recurse_1 (n, &n);
109 }
110 
111 int
112 main ()
113 {
114  sigset_t emptyset;
115  void *p;
116 
117 #if HAVE_SETRLIMIT && defined RLIMIT_STACK
118  /* Before starting the endless recursion, try to be friendly to the user's
119  machine. On some Linux 2.2.x systems, there is no stack limit for user
120  processes at all. We don't want to kill such systems. */
121  struct rlimit rl;
122  rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
123  setrlimit (RLIMIT_STACK, &rl);
124 #endif
125 
126  /* Prepare the storage for the alternate stack. */
127  prepare_alternate_stack ();
128 
129  /* Install the stack overflow handler. */
130  if (stackoverflow_install_handler (&stackoverflow_handler,
131  mystack, SIGSTKSZ)
132  < 0)
133  exit (2);
134 
135  /* Preparations. */
136 #if !HAVE_MMAP_ANON && !HAVE_MMAP_ANONYMOUS && HAVE_MMAP_DEVZERO
137  zero_fd = open ("/dev/zero", O_RDONLY, 0644);
138 #endif
139 
140  /* Setup some mmaped memory. */
141  p = mmap_zeromap ((void *) 0x12340000, 0x4000);
142  if (p == (void *)(-1))
143  {
144  fprintf (stderr, "mmap_zeromap failed.\n");
145  exit (2);
146  }
147  page = (unsigned long) p;
148 
149  /* Make it read-only. */
150  if (mprotect ((void *) page, 0x4000, PROT_READ) < 0)
151  {
152  fprintf (stderr, "mprotect failed.\n");
153  exit (2);
154  }
155 
156  /* Install the SIGSEGV handler. */
157  if (sigsegv_install_handler (&sigsegv_handler) < 0)
158  exit (2);
159 
160  /* Save the current signal mask. */
161  sigemptyset (&emptyset);
162  sigprocmask (SIG_BLOCK, &emptyset, &mainsigset);
163 
164  /* Provoke two stack overflows in a row. */
165  switch (setjmp (mainloop))
166  {
167  case -1:
168  printf ("emergency exit\n"); exit (1);
169  case 0: case 1:
170  printf ("Starting recursion pass %d.\n", pass + 1);
171  recurse (0);
172  printf ("no endless recursion?!\n"); exit (1);
173  case 2:
174  *(volatile int *) (page + 0x678) = 42;
175  break;
176  case 3:
177  *(volatile int *) 0 = 42;
178  break;
179  case 4:
180  break;
181  default:
182  abort ();
183  }
184 
185  /* Validate that the alternate stack did not overflow. */
186  check_alternate_stack_no_overflow ();
187 
188  printf ("Test passed.\n");
189  exit (0);
190 }
191 
192 #else
193 
194 int
196 {
197  return 77;
198 }
199 
200 #endif