[libunwind] [libunwind][PPC64] Fix two SIGSEGV bugs in libunwind on powerpc64le (PR #198371)
Piotr Kubaj via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 9 12:55:46 PDT 2026
https://github.com/pkubaj updated https://github.com/llvm/llvm-project/pull/198371
>From c20f287696d793c08097001ad4be945ce679991f Mon Sep 17 00:00:00 2001
From: Piotr Kubaj <pkubaj at FreeBSD.org>
Date: Mon, 18 May 2026 00:00:00 +0000
Subject: [PATCH] Fix unw_getcontext corrupting callee-saved VSX registers on
LE
On ppc64le, the PPC64_STVS macro saves each VS register by doing an
in-place `xxswapd n, n` to swap its two 64-bit elements into the
correct memory layout before calling stxvd2x. It never applies a
second xxswapd to restore the register before returning.
Since xxswapd is its own inverse, this permanently corrupts all 64 VS
registers saved by unw_getcontext -- including the callee-saved
f14-f31 (VSR14-VSR31) and VR20-VR31 (VSR52-VSR63). The corruption
persists after unw_getcontext returns into the caller, so any code
that uses these vector registers after an unwind backtrace sees wrong
values.
In practice this causes SIGSEGV inside hashbrown's reserve_rehash
when RUST_BACKTRACE=1 is set, because every panic calls
_Unwind_Backtrace -> unw_getcontext, corrupting VR20-VR31 before
hashbrown's SIMD comparison loop runs and producing an out-of-bounds
access.
Fix by adding a second `xxswapd n, n` immediately after the stxvd2x
store. The pair is a no-op on the architectural register while still
writing the correctly-ordered value to memory.
The existing FIXME noting that this whole dance goes away once pre-P9
LE support is dropped is retained and remains accurate.
---
libunwind/src/UnwindRegistersSave.S | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S
index ca9a97b18e764..ffec44452ff60 100644
--- a/libunwind/src/UnwindRegistersSave.S
+++ b/libunwind/src/UnwindRegistersSave.S
@@ -424,9 +424,13 @@ LnoR2Fix:
// register in the incorrect doubleword order.
// FIXME: when supporting targets older than Power9 on LE is no longer required
// this can be changed to simply `stxv n, 16 * n(4)`.
+// Restore the register after storing: xxswapd is its own inverse, so a second
+// xxswapd undoes the in-place corruption of callee-saved VSRs (f14-f31,
+// VR20-VR31) that would otherwise persist after unw_getcontext returns.
#define PPC64_STVS(n) \
xxswapd n, n ;\
stxvd2x n, 0, 4 ;\
+ xxswapd n, n ;\
addi 4, 4, 16
#else
#define PPC64_STVS(n) \
More information about the cfe-commits
mailing list