Hello fellow hackers!
My build farm animal "unicorn" has been sick for a while, apologies
for not jumping on that sooner, I'll get to that in another email.
This is a small issue that I found when trying to expand the testing
on my Windows/aarch64 host with two more animals, one for MSYS2 clang
and one with MinGW and gcc. This report/fix is fairly straight
forward in that it is a simple change in c.h for the MSYS2/clang on
aarch64 combo only.
I found that the build fails to compile as early as
src/common/pg_get_line.c, the first caller of sigsetjmp():
../pgsql/src/common/pg_get_line.c:129: error: incompatible pointer
types passing 'sigjmp_buf' (aka 'long long[5]') to parameter of
type 'void **' [-Wincompatible-pointer-types]
and, with a slightly different clang, the more fundamental:
error: __builtin_setjmp is not supported for the current target
Root cause
----------
c.h maps sigsetjmp()/siglongjmp() onto the gcc builtins for MinGW-64:
#ifdef WIN32
#ifdef __MINGW64__
typedef intptr_t sigjmp_buf[5];
#define sigsetjmp(x,y) __builtin_setjmp(x)
#define siglongjmp __builtin_longjmp
#else
...
This dates to commit 146cb3889c3 ("Work around issues in MinGW-64's
setjmp/longjmp support.", 2021), which was written for and tested on
x86_64 MinGW, where __builtin_setjmp works. On aarch64 MinGW
toolchains it does not:
* clang for aarch64-w64-windows-gnu does not implement
__builtin_setjmp at all; and
* where a builtin is accepted, its first parameter is a void **,
which is incompatible with the intptr_t sigjmp_buf[5] that the
same block declares.
So __MINGW64__ is too broad a condition: the builtin-setjmp workaround
is correct on x86_64 MinGW but wrong on aarch64 MinGW.
The underlying MinGW-64 setjmp bug that 146cb3889c3 works around is, as
far as I can tell, still unfixed: the attempt to narrow the workaround
to MSVCRT-only (c313fa4602d, "Use workaround of __builtin_setjmp only on
MINGW on MSVCRT") was reverted by 8f5e419484c because the problem "is
found to cause issues on x86_64 Windows even when using UCRT." So we
should keep the __builtin_setjmp path for x86_64 MinGW; this patch only
removes it where the builtin cannot be used at all.
Fix
---
Restrict the __builtin_setjmp path to !defined(__aarch64__), so that
aarch64 MinGW falls back to plain setjmp()/longjmp() -- the same path
already used for non-MinGW Windows toolchains. x86_64 MinGW is
unchanged.
I tested this fix on my host with the proposed changes and can confirm
that it fixes the issue and that the 2021 defect was GCC-x86_64-MinGW
specific.
Testing
-------
Built and tested on real aarch64 Windows 11 hardware with the MSYS2
clangarm64 toolchain (clang 22.1.8, target aarch64-w64-windows-gnu):
* Without the patch the tree fails to compile at
src/common/pg_get_line.c (the first sigsetjmp() caller), as above.
* With the patch the full tree builds cleanly (ninja: 2103/2103
targets, postgres.exe produced) and, importantly, the resulting
server exercises the setjmp/longjmp path correctly at runtime:
initdb succeeds; 25 consecutive elog(ERROR) cycles (each a
siglongjmp back to the main loop) are caught and recovered; nested
PL/pgSQL exception blocks work; the server stays healthy with no
TRAP/PANIC/crash in the log across the run.
So on this toolchain the plain setjmp()/longjmp() fallback is not merely
a compile fix -- it is runtime-correct. The original MinGW-64
setjmp/longjmp defect that 146cb3889c3 works around appears to be
specific to the x86_64 GCC MinGW toolchain and not present in
clang-aarch64-mingw, which has its own setjmp lowering. I have not
tested a GCC-based aarch64 MinGW toolchain.
I have not exercised a full check-world on this platform yet (that is
gated on a separate atomics issue I am handling in a different thread);
this result is initdb + targeted error-path testing, not the full
regression suite.
The patch is attached (v1). It applies on master and is a one-line
condition change plus a comment update; it changes no behavior on any
currently-supported platform (only aarch64 MinGW, which does not build
today, takes the new path). As is becoming more and more common, yes
I did use AI/LLMs to help diagnose, propose a fix, exhaustively test,
and write this email. I have reviewed the results, the patch, the
tests, and the email content myself and feel that this is a small but
important change that allows for use of Postgres on Windows 11 built
using MSYS2/clang on aarch64 hosts.
best,
-gregFrom b24fcc6f1c7a446c01588558eb85bf4fdd42506d Mon Sep 17 00:00:00 2001
From: Greg Burd <[email protected]>
Date: Sun, 26 Jul 2026 13:30:36 -0400
Subject: [PATCH v1] Don't use __builtin_setjmp on aarch64 MinGW/Windows
Commit 146cb3889c3 made the WIN32/MinGW-64 build use gcc's
__builtin_setjmp/__builtin_longjmp to work around longstanding issues
in MinGW-64's own setjmp support. That workaround is fine on x86_64
MinGW, but it is broken on aarch64 (ARM64) MinGW toolchains:
* clang for aarch64-w64-windows-gnu does not implement
__builtin_setjmp at all -- it errors with
"__builtin_setjmp is not supported for the current target"; and
* where the builtin is accepted its first argument is a void **,
which is incompatible with the intptr_t sigjmp_buf[5] that c.h
declares, producing
"incompatible pointer types passing 'sigjmp_buf' to parameter of
type 'void **'".
The net effect is that a PostgreSQL build with a clang-based aarch64
MinGW toolchain fails to compile as early as src/common/pg_get_line.c
(the first caller of sigsetjmp()).
Restrict the __builtin_setjmp path to !defined(__aarch64__) so that
aarch64 MinGW falls back to plain setjmp()/longjmp(), the same path
already used for non-MinGW Windows toolchains. x86_64 MinGW is
unchanged.
Reported while building for aarch64 Windows with an MSYS2 clangarm64
toolchain.
---
src/include/c.h | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/include/c.h b/src/include/c.h
index 20cfbac54e7..981f8c42f55 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -1525,18 +1525,23 @@ typedef struct pg_signal_info
* When there is no sigsetjmp, its functionality is provided by plain
* setjmp. We now support the case only on Windows. However, it seems
* that MinGW-64 has some longstanding issues in its setjmp support,
- * so on that toolchain we cheat and use gcc's builtins.
+ * so on that toolchain we cheat and use gcc's builtins. That workaround
+ * only applies to x86_64 MinGW: on aarch64 (ARM64) MinGW toolchains
+ * clang does not implement __builtin_setjmp/__builtin_longjmp at all
+ * ("__builtin_setjmp is not supported for the current target"), and its
+ * prototype takes a void ** rather than PostgreSQL's sigjmp_buf, so fall
+ * back to plain setjmp there.
*/
#ifdef WIN32
-#ifdef __MINGW64__
+#if defined(__MINGW64__) && !defined(__aarch64__)
typedef intptr_t sigjmp_buf[5];
#define sigsetjmp(x,y) __builtin_setjmp(x)
#define siglongjmp __builtin_longjmp
-#else /* !__MINGW64__ */
+#else /* !__MINGW64__ || __aarch64__ */
#define sigjmp_buf jmp_buf
#define sigsetjmp(x,y) setjmp(x)
#define siglongjmp longjmp
-#endif /* __MINGW64__ */
+#endif /* __MINGW64__ && !__aarch64__ */
#endif /* WIN32 */
/* /port compatibility functions */
--
2.51.2