Skip to content

Commit

Permalink
[ASan][test] Fix TestCases/Posix/stack-overflow.cpp on Solaris/sparcv9 (
Browse files Browse the repository at this point in the history
llvm#109101)

When ASan testing is enabled on SPARC as per PR llvm#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`.
  • Loading branch information
rorth authored and augusto2112 committed Sep 26, 2024
1 parent 112f758 commit 826c364
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 8 deletions.
18 changes: 16 additions & 2 deletions compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
15 changes: 9 additions & 6 deletions compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 826c364

Please sign in to comment.