Skip to content

Conversation

rorth
Copy link
Collaborator

@rorth rorth commented Aug 2, 2024

  UBSan-Standalone-sparc :: TestCases/Misc/Linux/diag-stacktrace.cpp

FAILs on 32 and 64-bit Linux/sparc64 (and on Solaris/sparcv9, too: the test isn't Linux-specific at all). With
UBSAN_OPTIONS=fast_unwind_on_fatal=1, the stack trace shows a duplicate innermost frame:

compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:14:31: runtime error: execution reached the end of a value-returning function without returning a value
    #0 0x7003a708 in f() compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:14:35
    #1 0x7003a708 in f() compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:14:35
    #2 0x7003a714 in g() compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:17:38

which isn't seen with fast_unwind_on_fatal=0.

This turns out to be another fallout from fixing
__builtin_return_address/__builtin_extract_return_addr on SPARC. In sanitizer_stacktrace_sparc.cpp (BufferedStackTrace::UnwindFast) the pc arg is the return address, while pc1 from the stack frame (fr_savpc) is the address of the call insn, leading to a double entry for the innermost frame in trace_buffer[].

This patch fixes this by moving the adjustment before all uses.

Tested on sparc64-unknown-linux-gnu and sparcv9-sun-solaris2.11 (with the ubsan/TestCases/Misc/Linux tests enabled).

```
  UBSan-Standalone-sparc :: TestCases/Misc/Linux/diag-stacktrace.cpp
```
`FAIL`s on 32 and 64-bit Linux/sparc64 (and on Solaris/sparcv9, too: the
test isn't Linux-specific at all).  With
`UBSAN_OPTIONS=fast_unwind_on_fatal=1`, the stack trace shows a duplicate
innermost frame:
```
compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:14:31: runtime error: execution reached the end of a value-returning function without returning a value
    #0 0x7003a708 in f() compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:14:35
    #1 0x7003a708 in f() compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:14:35
    llvm#2 0x7003a714 in g() compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:17:38
```
which isn't seen with `fast_unwind_on_fatal=0`.

This turns out to be another fallout from fixing
`__builtin_return_address`/`__builtin_extract_return_addr` on SPARC.  In
`sanitizer_stacktrace_sparc.cpp` (`BufferedStackTrace::UnwindFast`) the
`pc` arg is the return address, while `pc1` from the stack frame
(`fr_savpc`) is the address of the `call` insn, leading to a double entry
for the innermost frame in `trace_buffer[]`.

This patch fixes this by moving the adjustment before all uses.

Tested on `sparc64-unknown-linux-gnu` and `sparcv9-sun-solaris2.11` (with
the `ubsan/TestCases/Misc/Linux` tests enabled).
@llvmbot
Copy link
Member

llvmbot commented Aug 2, 2024

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Rainer Orth (rorth)

Changes
  UBSan-Standalone-sparc :: TestCases/Misc/Linux/diag-stacktrace.cpp

FAILs on 32 and 64-bit Linux/sparc64 (and on Solaris/sparcv9, too: the test isn't Linux-specific at all). With
UBSAN_OPTIONS=fast_unwind_on_fatal=1, the stack trace shows a duplicate innermost frame:

compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:14:31: runtime error: execution reached the end of a value-returning function without returning a value
    #<!-- -->0 0x7003a708 in f() compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:14:35
    #<!-- -->1 0x7003a708 in f() compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:14:35
    #<!-- -->2 0x7003a714 in g() compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:17:38

which isn't seen with fast_unwind_on_fatal=0.

This turns out to be another fallout from fixing
__builtin_return_address/__builtin_extract_return_addr on SPARC. In sanitizer_stacktrace_sparc.cpp (BufferedStackTrace::UnwindFast) the pc arg is the return address, while pc1 from the stack frame (fr_savpc) is the address of the call insn, leading to a double entry for the innermost frame in trace_buffer[].

This patch fixes this by moving the adjustment before all uses.

Tested on sparc64-unknown-linux-gnu and sparcv9-sun-solaris2.11 (with the ubsan/TestCases/Misc/Linux tests enabled).


Full diff: https://github.com/llvm/llvm-project/pull/101634.diff

1 Files Affected:

  • (modified) compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_sparc.cpp (+5-6)
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_sparc.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_sparc.cpp
index a2000798a3907..74f435287af3c 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_sparc.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_sparc.cpp
@@ -58,17 +58,16 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top,
   // Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
   while (IsValidFrame(bp, stack_top, bottom) && IsAligned(bp, sizeof(uhwptr)) &&
          size < max_depth) {
-    uhwptr pc1 = ((uhwptr *)bp)[15];
+    // %o7 contains the address of the call instruction and not the
+    // return address, so we need to compensate.
+    uhwptr pc1 = GetNextInstructionPc(((uhwptr *)bp)[15]);
     // Let's assume that any pointer in the 0th page is invalid and
     // stop unwinding here.  If we're adding support for a platform
     // where this isn't true, we need to reconsider this check.
     if (pc1 < kPageSize)
       break;
-    if (pc1 != pc) {
-      // %o7 contains the address of the call instruction and not the
-      // return address, so we need to compensate.
-      trace_buffer[size++] = GetNextInstructionPc((uptr)pc1);
-    }
+    if (pc1 != pc)
+      trace_buffer[size++] = pc1;
     bottom = bp;
     bp = (uptr)((uhwptr *)bp)[14] + STACK_BIAS;
   }

@rorth
Copy link
Collaborator Author

rorth commented Aug 2, 2024

@ebotcazou would be the natural reviewer, but for some reason I cannot select him.

@tru
Copy link
Collaborator

tru commented Aug 2, 2024

@ebotcazou would be the natural reviewer, but for some reason I cannot select him.

That's because he's not part of the GitHub organization.

@rorth rorth merged commit 3368a32 into llvm:main Aug 3, 2024
9 checks passed
@rorth
Copy link
Collaborator Author

rorth commented Aug 3, 2024

/cherry-pick 3368a32

llvmbot pushed a commit to llvmbot/llvm-project that referenced this pull request Aug 3, 2024
```
  UBSan-Standalone-sparc :: TestCases/Misc/Linux/diag-stacktrace.cpp
```
`FAIL`s on 32 and 64-bit Linux/sparc64 (and on Solaris/sparcv9, too: the
test isn't Linux-specific at all). With
`UBSAN_OPTIONS=fast_unwind_on_fatal=1`, the stack trace shows a
duplicate innermost frame:
```
compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:14:31: runtime error: execution reached the end of a value-returning function without returning a value
    #0 0x7003a708 in f() compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:14:35
    #1 0x7003a708 in f() compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:14:35
    #2 0x7003a714 in g() compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:17:38
```
which isn't seen with `fast_unwind_on_fatal=0`.

This turns out to be another fallout from fixing
`__builtin_return_address`/`__builtin_extract_return_addr` on SPARC. In
`sanitizer_stacktrace_sparc.cpp` (`BufferedStackTrace::UnwindFast`) the
`pc` arg is the return address, while `pc1` from the stack frame
(`fr_savpc`) is the address of the `call` insn, leading to a double
entry for the innermost frame in `trace_buffer[]`.

This patch fixes this by moving the adjustment before all uses.

Tested on `sparc64-unknown-linux-gnu` and `sparcv9-sun-solaris2.11`
(with the `ubsan/TestCases/Misc/Linux` tests enabled).

(cherry picked from commit 3368a32)
@llvmbot
Copy link
Member

llvmbot commented Aug 3, 2024

/pull-request #101848

kutemeikito added a commit to kutemeikito/llvm-project that referenced this pull request Aug 4, 2024
* 'main' of https://github.com/llvm/llvm-project:
  [RISCV] Improve hasAllNBitUsers for users of SLLI.
  [RISCV] Invert if conditions in the switch in RISCVDAGToDAGISel::hasAllNBitUsers. NFC
  [Transforms] Construct SmallVector with ArrayRef (NFC) (llvm#101851)
  [RISCV] Capitalize some variable names. NFC
  [sanitizer_common] Fix UnwindFast on SPARC (llvm#101634)
  [builtins] Fix divtc3.c etc. compilation on Solaris/SPARC with gcc (llvm#101662)
  [NFC][asan] Track current dynamic init module (llvm#101597)
  [libc] enable most of the entrypoints on aarch64 (llvm#101797)
  [SandboxIR][Tracker] Track InsertIntoBB (llvm#101595)
  [SCEV] Use const SCEV * explicitly in more places.
  [ELF] Move outputSections into Ctx. NFC
  [ELF] Move ElfSym into Ctx. NFC
  [ELF] Move Out into Ctx. NFC
  [test][asan] Fix the test checks
  [NFC][asan] Switch from list to DynInitGlobalsByModule (llvm#101596)

Signed-off-by: Edwiin Kusuma Jaya <[email protected]>
tru pushed a commit to llvmbot/llvm-project that referenced this pull request Aug 4, 2024
```
  UBSan-Standalone-sparc :: TestCases/Misc/Linux/diag-stacktrace.cpp
```
`FAIL`s on 32 and 64-bit Linux/sparc64 (and on Solaris/sparcv9, too: the
test isn't Linux-specific at all). With
`UBSAN_OPTIONS=fast_unwind_on_fatal=1`, the stack trace shows a
duplicate innermost frame:
```
compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:14:31: runtime error: execution reached the end of a value-returning function without returning a value
    #0 0x7003a708 in f() compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:14:35
    #1 0x7003a708 in f() compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:14:35
    #2 0x7003a714 in g() compiler-rt/test/ubsan/TestCases/Misc/Linux/diag-stacktrace.cpp:17:38
```
which isn't seen with `fast_unwind_on_fatal=0`.

This turns out to be another fallout from fixing
`__builtin_return_address`/`__builtin_extract_return_addr` on SPARC. In
`sanitizer_stacktrace_sparc.cpp` (`BufferedStackTrace::UnwindFast`) the
`pc` arg is the return address, while `pc1` from the stack frame
(`fr_savpc`) is the address of the `call` insn, leading to a double
entry for the innermost frame in `trace_buffer[]`.

This patch fixes this by moving the adjustment before all uses.

Tested on `sparc64-unknown-linux-gnu` and `sparcv9-sun-solaris2.11`
(with the `ubsan/TestCases/Misc/Linux` tests enabled).

(cherry picked from commit 3368a32)
rorth added a commit to rorth/llvm-project that referenced this pull request Oct 8, 2024
When investigating PR llvm#101634, it turned out that `UBSan-Standalone-sparc
:: TestCases/Misc/Linux/diag-stacktrace.cpp` isn't Linux-specific at all.
In fact, none of the `ubsan/TestCases/Misc/Linux` tests are.

Therefore this patch moves them to `Misc/Posix` instead.

Tested on `sparc64-unknown-linux-gnu`, `sparcv9-sun-solaris2.11`,
`x86_64-pc-linux-gnu`, and `amd64-pc-solaris2.11`.
rorth added a commit that referenced this pull request Oct 15, 2024
When investigating PR #101634, it turned out that
`UBSan-Standalone-sparc :: TestCases/Misc/Linux/diag-stacktrace.cpp`
isn't Linux-specific at all. In fact, none of the
`ubsan/TestCases/Misc/Linux` tests are.

Therefore this patch moves them to `Misc/Posix` instead.

Tested on `sparc64-unknown-linux-gnu`, `sparcv9-sun-solaris2.11`,
`x86_64-pc-linux-gnu`, and `amd64-pc-solaris2.11`.
DanielCChen pushed a commit to DanielCChen/llvm-project that referenced this pull request Oct 16, 2024
When investigating PR llvm#101634, it turned out that
`UBSan-Standalone-sparc :: TestCases/Misc/Linux/diag-stacktrace.cpp`
isn't Linux-specific at all. In fact, none of the
`ubsan/TestCases/Misc/Linux` tests are.

Therefore this patch moves them to `Misc/Posix` instead.

Tested on `sparc64-unknown-linux-gnu`, `sparcv9-sun-solaris2.11`,
`x86_64-pc-linux-gnu`, and `amd64-pc-solaris2.11`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging this pull request may close these issues.

4 participants