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,

-greg
From 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

Reply via email to