summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-10-25 11:33:21 -0700
committerKaz Kylheku <kaz@kylheku.com>2015-10-25 11:33:21 -0700
commit09f172c98f79f52a6e5c0e4ec87918a6e74aaccf (patch)
treebadd09ef01db2cfd8ce77fd6e86ada747319aa8f
parent329318ae4f9c180ed68ec484bb5e1acdcb3dec44 (diff)
downloadtxr-09f172c98f79f52a6e5c0e4ec87918a6e74aaccf.tar.gz
txr-09f172c98f79f52a6e5c0e4ec87918a6e74aaccf.tar.bz2
txr-09f172c98f79f52a6e5c0e4ec87918a6e74aaccf.zip
Stop using C library setjmp/longjmp.
TXR is moving to custom assembly-language routines. This is mainly motivated by a very dubious thing done in the GNU C Library setjmp and longjmp in the name of security. Evidently, glibc's setjmp "mangles" certain pointer values which are stored into the jmp_buf buffer. It's been that way since 2005, evidently. This means that, firstly, all along, the use of setjmp in gc.c to get registers into a buffer so they can be scanned has not actually worked properly. More importantly, this pointer mangling in setjmp and longjmp is very hostile to a stack copying implementation of delimited continuations. The reason is that continuations contain jmp_buf buffers, which get relocated in the process of capturing and reviving a continuation. Any pointers in a jmp_buf which point into the captured stack segment have to be fixed up to point into the relocated location. Mangled pointers make this difficult, requiring hacks which are specific to glibc and the machine architecture. We might as well implement a clean, well-behaved setjmp and longjmp. * Makefile (jmp.o): New object file. (dbg/%.o, opt/%.o): New rules for .S prerequisites. * args.c, arith.c, cadr.c, combi.c, cadr.c, combi.c, debug.c, eval.c, filter.c, glob.c, hash.c, lib.c, match.c, parser.c, rand.c, regex.c, signal.c, stream.c, struct.c, sysif.c, syslog.c, txr.c, unwind.c, utf8.c: Removed <setjmp.h> include. * gc.c: Switch to struct jmp and jmp_save, instead of jmp_buf and setjmp. * jmp.S: New source file. * signal.h (struct jmp): New struct type. (jmp_save, jmp_restore): New function declarations denoting assembly language routines in jmp.S. (extended_jmp_buf): Uses struct jmp instead of setjmp. (extended_setjmp): Use jmp_save instead of setjmp. (extended_longjmp): Use jmp_restore instead of longjmp.
-rw-r--r--Makefile14
-rw-r--r--args.c1
-rw-r--r--arith.c1
-rw-r--r--cadr.c1
-rw-r--r--combi.c1
-rw-r--r--debug.c1
-rw-r--r--eval.c1
-rw-r--r--filter.c1
-rw-r--r--gc.c5
-rw-r--r--glob.c1
-rw-r--r--hash.c1
-rw-r--r--jmp.S180
-rw-r--r--lib.c1
-rw-r--r--match.c1
-rw-r--r--parser.c1
-rw-r--r--rand.c1
-rw-r--r--regex.c1
-rw-r--r--signal.c1
-rw-r--r--signal.h81
-rw-r--r--stream.c1
-rw-r--r--struct.c1
-rw-r--r--sysif.c1
-rw-r--r--syslog.c1
-rw-r--r--txr.c1
-rw-r--r--unwind.c1
-rw-r--r--utf8.c1
26 files changed, 270 insertions, 32 deletions
diff --git a/Makefile b/Makefile
index bc0b488e..f718e40d 100644
--- a/Makefile
+++ b/Makefile
@@ -46,7 +46,7 @@ EXTRA_OBJS-y :=
OBJS := txr.o lex.yy.o y.tab.o match.o lib.o regex.o gc.o unwind.o stream.o
OBJS += arith.o hash.o utf8.o filter.o eval.o parser.o rand.o combi.o sysif.o
-OBJS += args.o lisplib.o cadr.o struct.o
+OBJS += args.o lisplib.o cadr.o struct.o jmp.o
OBJS-$(debug_support) += debug.o
OBJS-$(have_syslog) += syslog.o
OBJS-$(have_glob) += glob.o
@@ -122,6 +122,12 @@ dbg/%.o: $(top_srcdir)%.c
opt/%.o: $(top_srcdir)%.c
$(call COMPILE_C_WITH_DEPS,$(OPT_FLAGS))
+
+dbg/%.o: $(top_srcdir)%.S
+ $(call COMPILE_C_WITH_DEPS,)
+
+opt/%.o: $(top_srcdir)%.S
+ $(call COMPILE_C_WITH_DEPS,)
endif
dbg/%.o: %.c
@@ -130,6 +136,12 @@ dbg/%.o: %.c
opt/%.o: %.c
$(call COMPILE_C_WITH_DEPS,$(OPT_FLAGS))
+dbg/%.o: %.S
+ $(call COMPILE_C_WITH_DEPS,)
+
+opt/%.o: %.S
+ $(call COMPILE_C_WITH_DEPS,)
+
dbg/%-win.o: $(top_srcdir)%.c
$(call COMPILE_C_WITH_DEPS,-DCONFIG_WIN_MAIN=1)
diff --git a/args.c b/args.c
index 9e0a6b24..7f65fc9e 100644
--- a/args.c
+++ b/args.c
@@ -25,7 +25,6 @@
*/
#include <stddef.h>
-#include <setjmp.h>
#include <signal.h>
#include <string.h>
#include "config.h"
diff --git a/arith.c b/arith.c
index 3d526b5b..21036cf4 100644
--- a/arith.c
+++ b/arith.c
@@ -29,7 +29,6 @@
#include <string.h>
#include <wctype.h>
#include <stdarg.h>
-#include <setjmp.h>
#include <wchar.h>
#include <math.h>
#include <signal.h>
diff --git a/cadr.c b/cadr.c
index 057e4f57..2172dd9b 100644
--- a/cadr.c
+++ b/cadr.c
@@ -29,7 +29,6 @@
#include <dirent.h>
#include <stdarg.h>
#include <stdlib.h>
-#include <setjmp.h>
#include <limits.h>
#include <signal.h>
#include "config.h"
diff --git a/combi.c b/combi.c
index 8a7697a5..5acd65b6 100644
--- a/combi.c
+++ b/combi.c
@@ -25,7 +25,6 @@
*/
#include <wctype.h>
-#include <setjmp.h>
#include <wchar.h>
#include <signal.h>
#include "config.h"
diff --git a/debug.c b/debug.c
index 370d13bd..487ef2a9 100644
--- a/debug.c
+++ b/debug.c
@@ -29,7 +29,6 @@
#include <string.h>
#include <errno.h>
#include <dirent.h>
-#include <setjmp.h>
#include <stdarg.h>
#include <wchar.h>
#include <signal.h>
diff --git a/eval.c b/eval.c
index ea08c7b3..bff81a48 100644
--- a/eval.c
+++ b/eval.c
@@ -29,7 +29,6 @@
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
-#include <setjmp.h>
#include <stdarg.h>
#include <wchar.h>
#include <signal.h>
diff --git a/filter.c b/filter.c
index 0388ea9f..9a66bb34 100644
--- a/filter.c
+++ b/filter.c
@@ -25,7 +25,6 @@
*/
#include <stddef.h>
-#include <setjmp.h>
#include <string.h>
#include <wctype.h>
#include <wchar.h>
diff --git a/gc.c b/gc.c
index ed8cd04c..7762a3a2 100644
--- a/gc.c
+++ b/gc.c
@@ -28,7 +28,6 @@
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
-#include <setjmp.h>
#include <dirent.h>
#include <wchar.h>
#include <signal.h>
@@ -58,10 +57,10 @@ typedef struct heap {
} heap_t;
typedef struct mach_context {
- jmp_buf buf;
+ struct jmp buf;
} mach_context_t;
-#define save_context(X) setjmp((X).buf)
+#define save_context(X) jmp_save(&(X).buf)
int opt_gc_debug;
#if HAVE_VALGRIND
diff --git a/glob.c b/glob.c
index 58b0d0e9..b3a39d92 100644
--- a/glob.c
+++ b/glob.c
@@ -27,7 +27,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
-#include <setjmp.h>
#include <wchar.h>
#include <signal.h>
#include <glob.h>
diff --git a/hash.c b/hash.c
index 33455f36..d6092efa 100644
--- a/hash.c
+++ b/hash.c
@@ -30,7 +30,6 @@
#include <dirent.h>
#include <stdarg.h>
#include <stdlib.h>
-#include <setjmp.h>
#include <limits.h>
#include <signal.h>
#include "config.h"
diff --git a/jmp.S b/jmp.S
new file mode 100644
index 00000000..9784d5d7
--- /dev/null
+++ b/jmp.S
@@ -0,0 +1,180 @@
+/* Copyright 2009-2015
+ * Kaz Kylheku <kaz@kylheku.com>
+ * Vancouver, Canada
+ * All rights reserved.
+ *
+ * Redistribution of this software in source and binary forms, with or without
+ * modification, is permitted provided that the following two conditions are met.
+ *
+ * Use of this software in any manner constitutes agreement with the disclaimer
+ * which follows the two conditions.
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DAMAGES, HOWEVER CAUSED,
+ * AND UNDER ANY THEORY OF LIABILITY, ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if __MINGW32__ || __CYGWIN32__
+#define DEFUN(NAME) \
+.global _ ## NAME ; \
+_ ## NAME: ;
+#elif __APPLE__
+#define DEFUN(NAME) \
+.globl _ ## NAME ; \
+_ ## NAME: ;
+#elif __arm__ && !__thumb__
+#define DEFUN(NAME) \
+.text ; \
+.align 4 ; \
+.global NAME ; \
+.type NAME, %function ; \
+NAME: ;
+#elif __arm__ && __thumb__
+#define DEFUN(NAME) \
+.text ; \
+.align 4 ; \
+.global NAME ; \
+.thumb ; \
+.thumb_func ; \
+.type NAME, %function ; \
+NAME: ;
+#else
+#define DEFUN(NAME) \
+.global NAME ; \
+.type NAME, @function ; \
+NAME: ;
+#endif
+
+#if __i386__
+
+#define JEIP 0
+#define JESP 4
+#define JEBP 8
+#define JEBX 12
+#define JESI 16
+#define JEDI 20
+
+#define RETA 0
+#define ARG1 4
+#define ARG2 8
+
+DEFUN(jmp_save)
+ movl RETA(%esp), %ecx
+ movl ARG1(%esp), %eax
+ movl %ecx, JEIP(%eax)
+ leal ARG1(%esp), %ecx
+ movl %ecx, JESP(%eax)
+ movl %ebp, JEBP(%eax)
+ movl %ebx, JEBX(%eax)
+ movl %esi, JESI(%eax)
+ movl %edi, JEDI(%eax)
+ xorl %eax, %eax
+ ret
+
+DEFUN(jmp_restore)
+ movl ARG1(%esp), %edx
+ movl ARG2(%esp), %eax
+ mov JEDI(%edx),%edi
+ mov JESI(%edx),%esi
+ mov JEBX(%edx),%ebx
+ mov JEBP(%edx),%ebp
+ mov JESP(%edx),%ecx
+ mov %ecx,%esp
+ mov JEIP(%edx),%ecx
+ jmp *%ecx
+
+#elif __x86_64__
+
+#define JRIP 0
+#define JRSP 8
+#define JRBP 16
+#define JRBX 24
+#define JR12 32
+#define JR13 40
+#define JR14 48
+#define JR15 56
+
+#define RETA 0
+#define ARG2 8
+
+DEFUN(jmp_save)
+ mov RETA(%rsp), %rdx
+ mov %rdx, JRIP(%rdi)
+ lea ARG2(%rsp), %rdx
+ mov %rdx, JRSP(%rdi)
+ mov %rbp, JRBP(%rdi)
+ mov %rbx, JRBX(%rdi)
+ mov %r12, JR12(%rdi)
+ mov %r13, JR13(%rdi)
+ mov %r14, JR14(%rdi)
+ mov %r15, JR15(%rdi)
+ xor %rax, %rax
+ ret
+
+DEFUN(jmp_restore)
+ mov JR15(%rdi), %r15
+ mov JR14(%rdi), %r14
+ mov JR13(%rdi), %r13
+ mov JR12(%rdi), %r12
+ mov JRBX(%rdi), %rbx
+ mov JRBP(%rdi), %rbp
+ mov JRSP(%rdi), %rdx
+ mov %rdx, %rsp
+ mov JRIP(%rdi), %rdx
+ mov %rsi, %rax
+ jmp *%rdx
+
+#elif __arm__ && !__thumb__
+
+DEFUN(jmp_save)
+ stmia r0, {r4, r5, r6, r7, r8, r9, r10, fp, sp, lr}
+ mov r0, #0
+ bx lr
+
+DEFUN(jmp_restore)
+ ldmia r0, {r4, r5, r6, r7, r8, r9, r10, fp, sp, lr}
+ mov r0, r1
+ bx lr
+
+#elif __arm__ && __thumb__
+
+DEFUN(jmp_save)
+ mov r2, r0
+ mov r3, lr
+ stmia r0!, {r3, r4, r5, r6, r7}
+ mov r3, r8
+ mov r4, r9
+ mov r5, r10
+ mov r6, fp
+ mov r7, sp
+ stmia r0!, {r3, r4, r5, r6, r7}
+ ldmia r2!, {r3, r4, r5, r6, r7}
+ mov r0, #0
+ bx lr
+
+DEFUN(jmp_restore)
+ mov r2, r0
+ add r0, #5*4
+ ldmia r0!, {r3, r4, r5, r6, r7}
+ mov r8, r3
+ mov r9, r4
+ mov r10, r5
+ mov fp, r6
+ mov sp, r7
+ ldmia r2!, {r3, r4, r5, r6, r7}
+ mov r0, r1
+ bx r3
+
+#else
+#error port me!
+#endif
diff --git a/lib.c b/lib.c
index 15986952..21f27816 100644
--- a/lib.c
+++ b/lib.c
@@ -32,7 +32,6 @@
#include <limits.h>
#include <stdarg.h>
#include <dirent.h>
-#include <setjmp.h>
#include <errno.h>
#include <wchar.h>
#include <math.h>
diff --git a/match.c b/match.c
index 7a521416..98b35cbc 100644
--- a/match.c
+++ b/match.c
@@ -30,7 +30,6 @@
#include <string.h>
#include <errno.h>
#include <dirent.h>
-#include <setjmp.h>
#include <stdarg.h>
#include <wchar.h>
#include <signal.h>
diff --git a/parser.c b/parser.c
index 9acfa0da..6caa3a41 100644
--- a/parser.c
+++ b/parser.c
@@ -31,7 +31,6 @@
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
-#include <setjmp.h>
#include <wchar.h>
#include <signal.h>
#include <ctype.h>
diff --git a/rand.c b/rand.c
index b127dae0..04c161be 100644
--- a/rand.c
+++ b/rand.c
@@ -31,7 +31,6 @@
#include <limits.h>
#include <stdarg.h>
#include <dirent.h>
-#include <setjmp.h>
#include <wchar.h>
#include <limits.h>
#include <time.h>
diff --git a/regex.c b/regex.c
index 823f0c4e..79692803 100644
--- a/regex.c
+++ b/regex.c
@@ -30,7 +30,6 @@
#include <wchar.h>
#include <assert.h>
#include <dirent.h>
-#include <setjmp.h>
#include <dirent.h>
#include <limits.h>
#include <signal.h>
diff --git a/signal.c b/signal.c
index 05554a64..c3b9a351 100644
--- a/signal.c
+++ b/signal.c
@@ -28,7 +28,6 @@
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
-#include <setjmp.h>
#include <errno.h>
#include <wchar.h>
#include <dirent.h>
diff --git a/signal.h b/signal.h
index 9dc076cd..dc5b44ba 100644
--- a/signal.h
+++ b/signal.h
@@ -40,6 +40,75 @@ extern int debug_depth;
#define EJ_OPT_SAVE(EJB) EJ_DBG_SAVE(EJB)
#define EJ_OPT_REST(EJB) EJ_DBG_REST(EJB)
+#if __i386__
+
+struct jmp {
+ unsigned eip;
+ unsigned esp;
+ unsigned ebp;
+ unsigned ebx;
+ unsigned esi;
+ unsigned edi;
+};
+
+#elif __x86_64__
+
+struct jmp {
+ unsigned long rip;
+ unsigned long rsp;
+ unsigned long rbp;
+ unsigned long rbx;
+ unsigned long r12;
+ unsigned long r13;
+ unsigned long r14;
+ unsigned long r15;
+};
+
+#elif __arm__ && !__thumb__
+
+struct jmp {
+ unsigned long r4;
+ unsigned long r5;
+ unsigned long r6;
+ unsigned long r7;
+ unsigned long r8;
+ unsigned long r9;
+ unsigned long r10;
+ unsigned long fp;
+ unsigned long sp;
+ unsigned long lr;
+};
+
+#elif __arm__ && __thumb__
+
+struct jmp {
+ unsigned long lr;
+ unsigned long r4;
+ unsigned long r5;
+ unsigned long r6;
+ unsigned long r7;
+ unsigned long r8;
+ unsigned long r9;
+ unsigned long r10;
+ unsigned long fp;
+ unsigned long sp;
+};
+
+#else
+#error port me!
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int jmp_save(struct jmp *);
+void jmp_restore(struct jmp *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
#if HAVE_POSIX_SIGS
INLINE void copy_sigset(volatile sigset_t *dest, const sigset_t *src)
@@ -88,7 +157,7 @@ INLINE val sig_check_fast(void)
}
typedef struct {
- jmp_buf jb;
+ struct jmp jb;
volatile sig_atomic_t se;
volatile sigset_t blocked;
volatile val de;
@@ -99,7 +168,7 @@ typedef struct {
} extended_jmp_buf;
#define extended_setjmp(EJB) \
- (setjmp((EJB).jb) \
+ (jmp_save(&(EJB).jb) \
? (async_sig_enabled = (EJB).se, \
dyn_env = (EJB).de, \
gc_enabled = (EJB).gc, \
@@ -119,7 +188,7 @@ typedef struct {
0))
#define extended_longjmp(EJB, ARG) \
- ((EJB).rv = (ARG), longjmp((EJB).jb, 1))
+ ((EJB).rv = (ARG), jmp_restore(&(EJB).jb, 1))
extern sigset_t sig_blocked_cache;
extern volatile sig_atomic_t async_sig_enabled;
@@ -135,7 +204,7 @@ extern volatile sig_atomic_t async_sig_enabled;
#define sig_check_fast() ((void) 0)
typedef struct {
- jmp_buf jb;
+ struct jmp jb;
volatile val de;
volatile int gc;
val **volatile gc_pt;
@@ -144,7 +213,7 @@ typedef struct {
} extended_jmp_buf;
#define extended_setjmp(EJB) \
- (setjmp((EJB).jb) \
+ (jmp_save(&(EJB).jb) \
? (dyn_env = (EJB).de, \
gc_enabled = ((EJB).gc), \
gc_prot_top = (EJB).gc_pt, \
@@ -157,7 +226,7 @@ typedef struct {
0))
#define extended_longjmp(EJB, ARG) \
- ((EJB).rv = (ARG), longjmp((EJB).jb, 1))
+ ((EJB).rv = (ARG), jmp_restore(&(EJB).jb, 1))
extern int async_sig_enabled;
diff --git a/stream.c b/stream.c
index 024591e4..275de1bb 100644
--- a/stream.c
+++ b/stream.c
@@ -30,7 +30,6 @@
#include <dirent.h>
#include <stdarg.h>
#include <stdlib.h>
-#include <setjmp.h>
#include <errno.h>
#include <ctype.h>
#include <wchar.h>
diff --git a/struct.c b/struct.c
index 87f1ebb7..24d65363 100644
--- a/struct.c
+++ b/struct.c
@@ -30,7 +30,6 @@
#include <dirent.h>
#include <stdarg.h>
#include <stdlib.h>
-#include <setjmp.h>
#include <limits.h>
#include <signal.h>
#include "config.h"
diff --git a/sysif.c b/sysif.c
index 1fe92471..b4f2df52 100644
--- a/sysif.c
+++ b/sysif.c
@@ -28,7 +28,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <setjmp.h>
#include <wchar.h>
#include <signal.h>
#include <dirent.h>
diff --git a/syslog.c b/syslog.c
index aa3539c3..275b188e 100644
--- a/syslog.c
+++ b/syslog.c
@@ -28,7 +28,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
-#include <setjmp.h>
#include <wchar.h>
#include <signal.h>
#include <dirent.h>
diff --git a/txr.c b/txr.c
index 36937ffe..f9d20fdb 100644
--- a/txr.c
+++ b/txr.c
@@ -29,7 +29,6 @@
#include <string.h>
#include <limits.h>
#include <dirent.h>
-#include <setjmp.h>
#include <stdarg.h>
#include <wchar.h>
#include <signal.h>
diff --git a/unwind.c b/unwind.c
index 79b9a7fd..0e075306 100644
--- a/unwind.c
+++ b/unwind.c
@@ -29,7 +29,6 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
-#include <setjmp.h>
#include <dirent.h>
#include <stdarg.h>
#include <signal.h>
diff --git a/utf8.c b/utf8.c
index a09e082b..af81e99d 100644
--- a/utf8.c
+++ b/utf8.c
@@ -28,7 +28,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
-#include <setjmp.h>
#include <signal.h>
#include "config.h"
#include "lib.h"