From 69c61c3d9ae8f7397d64570412655007ea086c56 Mon Sep 17 00:00:00 2001
From: ShengYi Hung <aokblast@FreeBSD.org>
Date: Sun, 23 Aug 2026 12:45:10 +0800
Subject: [PATCH] meson: Fix unwinding error in libunwind over glibc

glibc's pthread_cancel dlopens libgcc_s.so.1 and uses its unwinder,
while libc++abi's personality routine resolves the Unwind* accessors
from the global scope, where LLVM libunwind wins. This causes the two
unwinders to interpret each other's unwind context incorrectly, and
cancelling a thread segfaults. Pull libgcc_s into DT_NEEDED before
libc++abi/libunwind so all Unwind* symbols resolve to the same unwinder.
---
 meson.build | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index 5dc7338d5f..88be32e27b 100644
--- a/meson.build
+++ b/meson.build
@@ -17,7 +17,17 @@ cpp_link_args = []
 
 if get_option('libcxx')
     cpp_args += ['-stdlib=libc++']
-    cpp_link_args += ['-stdlib=libc++', '-lc++abi']
+    cpp_link_args += ['-stdlib=libc++']
+    # glibc's pthread_cancel dlopens libgcc_s.so.1 and forces the unwind through
+    # that unwinder, while libc++abi's personality routine resolves the _Unwind_*
+    # accessors through the global scope, where LLVM libunwind wins. The two read
+    # each other's unwind context as their own, so cancelling a thread
+    # (SleeperThread::stop) segfaults. Pull libgcc_s into DT_NEEDED ahead of
+    # libc++abi/libunwind so every _Unwind_* symbol resolves to one unwinder.
+    if compiler.has_link_argument('-lgcc_s')
+        cpp_link_args += ['-Wl,--push-state,--no-as-needed', '-lgcc_s', '-Wl,--pop-state']
+    endif
+    cpp_link_args += ['-lc++abi']
 endif
 
 if compiler.has_link_argument('-lc++fs')
