From f9222ec96209c59c9a9a409c019ff59c0c20917c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20K=C3=A4ppler?= Date: Sat, 7 Sep 2024 22:52:22 +0200 Subject: [PATCH] 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. --- libguile/Makefile.am | 1 + libguile/continuations.h | 4 ++++ libguile/dynstack.c | 5 +++++ libguile/dynstack.h | 5 +++++ libguile/intrinsics.h | 4 ++++ libguile/setjump-win.h | 17 +++++++++++++++++ libguile/vm.h | 4 ++++ 7 files changed, 40 insertions(+) create mode 100644 libguile/setjump-win.h diff --git a/libguile/Makefile.am b/libguile/Makefile.am index 0890acc18..bf8893cf2 100644 --- a/libguile/Makefile.am +++ b/libguile/Makefile.am @@ -682,6 +682,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 +#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 + +#ifndef _WIN64 #include +#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 +#else +#include "libguile/setjump-win.h" +#endif + #include #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 +#else +#include "libguile/setjump-win.h" +#endif #include 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 + +/* 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 +#else +#include "libguile/setjump-win.h" +#endif #include #include -- 2.34.1