aboutsummaryrefslogtreecommitdiffstats
path: root/stackoverflow-recovery.c
diff options
context:
space:
mode:
Diffstat (limited to 'stackoverflow-recovery.c')
-rw-r--r--stackoverflow-recovery.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/stackoverflow-recovery.c b/stackoverflow-recovery.c
new file mode 100644
index 0000000..436c8c7
--- /dev/null
+++ b/stackoverflow-recovery.c
@@ -0,0 +1,75 @@
+/* See LICENSE file for copyright and license details. */
+#include <setjmp.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+unsigned volatile just_one = 1;
+
+static jmp_buf jmpenv;
+
+
+static void
+sigsegv(int signo)
+{
+ (void) signo;
+
+ siglongjmp(jmpenv, 1);
+}
+
+
+static unsigned
+overflow2(size_t depth)
+{
+ if (!depth)
+ return just_one;
+ depth -= 1u;
+ return overflow2(depth) + overflow2(depth);
+}
+
+
+static unsigned
+overflow(void)
+{
+ return overflow2(SIZE_MAX);
+}
+
+
+int
+main(void)
+{
+ volatile unsigned sum = 0;
+ volatile int i;
+ struct sigaction sa;
+ stack_t ss;
+
+ ss.ss_sp = malloc((size_t)SIGSTKSZ);
+ if (!ss.ss_sp)
+ return 1;
+ ss.ss_size = (size_t)SIGSTKSZ;
+ ss.ss_flags = 0;
+ if (sigaltstack(&ss, NULL))
+ return 2;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_ONSTACK;
+ sa.sa_handler = &sigsegv;
+ sigfillset(&sa.sa_mask);
+ sigaction(SIGSEGV, &sa, NULL);
+
+ for (i = 1; i <= 10; i++) {
+ if (!sigsetjmp(jmpenv, 1)) {
+ printf("%i: before overflow dereference\n", i);
+ sum += overflow();
+ } else {
+ printf("%i: after overflow dereference\n", i);
+ }
+ }
+
+ fflush(stdout);
+ return (int)sum;
+}