[compiler-rt] [ASan][test] Fix TestCases/Posix/stack-overflow.cpp on Solaris/sparcv9 (PR #109101)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 18 01:56:47 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-compiler-rt-sanitizer
Author: Rainer Orth (rorth)
<details>
<summary>Changes</summary>
When ASan testing is enabled on SPARC as per PR #<!-- -->107405, the
```
AddressSanitizer-sparc-sunos :: TestCases/Posix/stack-overflow.cpp
```
test `FAIL`s:
```
compiler-rt/test/asan/TestCases/Posix/stack-overflow.cpp:80:12: error: CHECK: expected string not found in input
// CHECK: {{stack-overflow on address 0x.* \(pc 0x.* bp 0x.* sp 0x.* T.*\)}}
^
AddressSanitizer:DEADLYSIGNAL
AddressSanitizer:DEADLYSIGNAL
=================================================================
==11358==ERROR: AddressSanitizer: SEGV on unknown address 0xff3fff90 (pc 0x000db0c0 bp 0xfeed59f8 sp 0xfeed5978 T0)
==11358==The signal is caused by a READ memory access.
AddressSanitizer:DEADLYSIGNAL
AddressSanitizer: nested bug in the same thread, aborting.
```
It turns out that `sanitizer_linux.cpp` (`GetPcSpBp`) tries to dereference the stack pointer to get at the saved frame pointer, which cannot work since `sp` has been invalidated by the stack overflow in the test. The access attempt thus leads to a second `SEGV`.
Solaris `walkcontext(3C)` doesn't have that problem: in the original OpenSolaris sources (`$SRC/lib/libc/port/gen/walkstack.c`) they used `/proc/self/as` to avoid the fault, which is quite heavy-handed. Solaris 11.4 uses a non-faulting load instead (`load_no_fault_uint32`, which just uses the `lduwa` insn).
This patch follows this lead, returning a `NULL` `bp` in the failure case. Unfortunately, this leads to `SEGV`s in the depth of the unwinder, so this patch avoids printing a stack trace in this case.
Tested on `sparcv9-sun-solaris2.11` and `sparc64-unknown-linux-gnu`.
---
Full diff: https://github.com/llvm/llvm-project/pull/109101.diff
2 Files Affected:
- (modified) compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp (+16-2)
- (modified) compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp (+9-6)
``````````diff
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
index 6359f4348e3c48..1da3ce763302e3 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
@@ -107,7 +107,9 @@ extern struct ps_strings *__ps_strings;
# endif // SANITIZER_NETBSD
# if SANITIZER_SOLARIS
+# include <stddef.h>
# include <stdlib.h>
+# include <sys/frame.h>
# include <thread.h>
# define environ _environ
# endif
@@ -2617,7 +2619,19 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
# if SANITIZER_SOLARIS
ucontext_t *ucontext = (ucontext_t *)context;
*pc = ucontext->uc_mcontext.gregs[REG_PC];
- *sp = ucontext->uc_mcontext.gregs[REG_O6] + STACK_BIAS;
+ *sp = ucontext->uc_mcontext.gregs[REG_SP] + STACK_BIAS;
+ // Avoid SEGV when dereferencing sp on stack overflow with non-faulting load.
+ // This requires a SPARC V9 CPU. Cannot use #ASI_PNF here: only supported
+ // since clang-19.
+# if defined(__sparcv9)
+ asm("ldxa [%[fp]] 0x82, %[bp]"
+# else
+ asm("lduwa [%[fp]] 0x82, %[bp]"
+# endif
+ : [bp] "=r"(*bp)
+ : [fp] "r"(&((struct frame *)*sp)->fr_savfp));
+ if (*bp)
+ *bp += STACK_BIAS;
# else
// Historical BSDism here.
struct sigcontext *scontext = (struct sigcontext *)context;
@@ -2628,8 +2642,8 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
*pc = scontext->si_regs.pc;
*sp = scontext->si_regs.u_regs[14];
# endif
-# endif
*bp = (uptr)((uhwptr *)*sp)[14] + STACK_BIAS;
+# endif
# elif defined(__mips__)
ucontext_t *ucontext = (ucontext_t *)context;
*pc = ucontext->uc_mcontext.pc;
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
index ffbaf1468ec8ff..351e00db6fb2dc 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
@@ -227,12 +227,15 @@ static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid,
SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc,
(void *)sig.bp, (void *)sig.sp, tid);
Printf("%s", d.Default());
- InternalMmapVector<BufferedStackTrace> stack_buffer(1);
- BufferedStackTrace *stack = stack_buffer.data();
- stack->Reset();
- unwind(sig, unwind_context, stack);
- stack->Print();
- ReportErrorSummary(kDescription, stack);
+ // Avoid SEGVs in the unwinder when bp couldn't be determined.
+ if (sig.bp) {
+ InternalMmapVector<BufferedStackTrace> stack_buffer(1);
+ BufferedStackTrace *stack = stack_buffer.data();
+ stack->Reset();
+ unwind(sig, unwind_context, stack);
+ stack->Print();
+ ReportErrorSummary(kDescription, stack);
+ }
}
static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
``````````
</details>
https://github.com/llvm/llvm-project/pull/109101
More information about the llvm-commits
mailing list