summaryrefslogtreecommitdiffstats
path: root/signal.h
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 /signal.h
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.
Diffstat (limited to 'signal.h')
-rw-r--r--signal.h81
1 files changed, 75 insertions, 6 deletions
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;