summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Käppler <xmichael-k@web.de>2024-09-07 22:52:22 +0200
committerLudovic Courtès <ludo@gnu.org>2024-10-20 12:14:21 +0200
commit08e26836f1116fba4ef1b674f2f9b37e0e4ebb03 (patch)
tree48385f78061d1a3854a097427088b41639dc029c
parentc0bfa3219cb9a0b9f5a0185caa1d8c5b5cd33fd2 (diff)
downloadguile-08e26836f1116fba4ef1b674f2f9b37e0e4ebb03.tar.gz
Fix setjmp/longjmp-related crashes on Windows
* libguile/Makefile.am: add new header file setjump-win.h * libguile/continuations.h, libguile/dynstack.c, libguile/dynstack.h, libguile/intrinsics.h, libguile/vm.h: supply custom `setjmp` macro on Windows Mingw implements `setjmp (env)` as a macro that expands to _setjmp (env, faddr) where `faddr` is set to the current frame address. This address is then stored as first element in the jump buffer `env`. When `longjmp` is called, it tries to unwind the stack up to the saved address by calling `RtlUnwindEx` from MSVCRT, which will fail, if the stack frames are interwoven with JIT-generated code, that violate the Windows x64 calling conventions. Thus implement the macro ourselves as _setjmp (env, NULL) which will toggle a code path in `longjmp` that does no unwinding. Signed-off-by: Ludovic Courtès <ludo@gnu.org>
-rw-r--r--libguile/Makefile.am1
-rw-r--r--libguile/continuations.h4
-rw-r--r--libguile/dynstack.c5
-rw-r--r--libguile/dynstack.h5
-rw-r--r--libguile/intrinsics.h4
-rw-r--r--libguile/setjump-win.h17
-rw-r--r--libguile/vm.h4
7 files changed, 40 insertions, 0 deletions
diff --git a/libguile/Makefile.am b/libguile/Makefile.am
index 59fb5f5fc..5f279a257 100644
--- a/libguile/Makefile.am
+++ b/libguile/Makefile.am
@@ -678,6 +678,7 @@ modinclude_HEADERS = \
rw.h \
scmsigs.h \
script.h \
+ setjump-win.h \
simpos.h \
smob.h \
snarf.h \
diff --git a/libguile/continuations.h b/libguile/continuations.h
index d83bed9b7..ac636512e 100644
--- a/libguile/continuations.h
+++ b/libguile/continuations.h
@@ -22,7 +22,11 @@
+#ifndef _WIN64
#include <setjmp.h>
+#else
+#include "libguile/setjump-win.h"
+#endif
#include "libguile/programs.h"
#include "libguile/throw.h"
diff --git a/libguile/dynstack.c b/libguile/dynstack.c
index 2eec7a7eb..e4ed878c2 100644
--- a/libguile/dynstack.c
+++ b/libguile/dynstack.c
@@ -25,7 +25,12 @@
#endif
#include <assert.h>
+
+#ifndef _WIN64
#include <setjmp.h>
+#else
+#include "setjump-win.h"
+#endif
#include "control.h"
#include "eval.h"
diff --git a/libguile/dynstack.h b/libguile/dynstack.h
index 4c32a0943..6f0775e40 100644
--- a/libguile/dynstack.h
+++ b/libguile/dynstack.h
@@ -22,7 +22,12 @@
+#ifndef _WIN64
#include <setjmp.h>
+#else
+#include "libguile/setjump-win.h"
+#endif
+
#include <signal.h>
#include "libguile/scm.h"
diff --git a/libguile/intrinsics.h b/libguile/intrinsics.h
index d2ffc847e..8a1c7c04e 100644
--- a/libguile/intrinsics.h
+++ b/libguile/intrinsics.h
@@ -24,7 +24,11 @@
#error intrinsics.h is private and uninstalled
#endif
+#ifndef _WIN64
#include <setjmp.h>
+#else
+#include "libguile/setjump-win.h"
+#endif
#include <libguile/scm.h>
diff --git a/libguile/setjump-win.h b/libguile/setjump-win.h
new file mode 100644
index 000000000..bf06e868b
--- /dev/null
+++ b/libguile/setjump-win.h
@@ -0,0 +1,17 @@
+#ifndef _SCM_SETJUMP_WIN_H_
+#define _SCM_SETJUMP_WIN_H_
+
+#include <setjmp.h>
+
+/* On Windows, `setjmp` expands to _setjmp, which takes a second
+ parameter that is set to the current frame address by default.
+ The address is then stored as first element in the jump buffer.
+ When `longjmp` is called, it tries to unwind the stack up
+ to the saved address, which will fail, if the stack frames are
+ interwoven with JIT-generated code.
+ Set the second parameter to NULL to prevent unwinding. */
+#undef setjmp
+#define setjmp(env) _setjmp(env, NULL)
+
+#endif /* _SCM_SETJUMP_WIN_H_ */
+
diff --git a/libguile/vm.h b/libguile/vm.h
index 9681188bd..d5b7138d3 100644
--- a/libguile/vm.h
+++ b/libguile/vm.h
@@ -20,7 +20,11 @@
#ifndef _SCM_VM_H_
#define _SCM_VM_H_
+#ifndef _WIN64
#include <setjmp.h>
+#else
+#include "libguile/setjump-win.h"
+#endif
#include <libguile/gc.h>
#include <libguile/programs.h>