[libunwind] [libunwind] Detect cycles of length 1 (PR #103476)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 13 14:39:45 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libunwind
Author: Michael Kolupaev (al13n321)
<details>
<summary>Changes</summary>
If an unwind step leaves both the instruction pointer and the stack pointer unchanged, stop unwinding. Otherwise we'd be stuck in a loop producing the same stack frame over and over.
This happens with musl libc in __clone(), which has incorrect DWARF unwind information.
GDB also handles it using cycle detection, but it checks for cycles of any length rather than just length 1. That seems unnecessary here, at least until anyone encounters such cycles in practice.
Tested manually in https://github.com/ClickHouse/libunwind/pull/33
---
Full diff: https://github.com/llvm/llvm-project/pull/103476.diff
1 Files Affected:
- (modified) libunwind/src/UnwindCursor.hpp (+11)
``````````diff
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index ce6dced535e781..b6c51446cb7d47 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -2923,6 +2923,9 @@ template <typename A, typename R> int UnwindCursor<A, R>::step(bool stage2) {
if (_unwindInfoMissing)
return UNW_STEP_END;
+ unw_word_t previousIP = getReg(UNW_REG_IP);
+ unw_word_t previousSP = getReg(UNW_REG_SP);
+
// Use unwinding info to modify register set as if function returned.
int result;
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
@@ -2951,6 +2954,14 @@ template <typename A, typename R> int UnwindCursor<A, R>::step(bool stage2) {
// update info based on new PC
if (result == UNW_STEP_SUCCESS) {
+ // Detect cycles of length 1. In particular this happens in musl's
+ // __clone(), which has incorrect DWARF unwind information.
+ // We don't check all registers, so it's not strictly guaranteed that
+ // unwinding would be stuck in a cycle, but seems like a reasonable
+ // heuristic.
+ if (getReg(UNW_REG_SP) == previousSP && getReg(UNW_REG_IP) == previousIP)
+ return UNW_EBADFRAME;
+
this->setInfoBasedOnIPRegister(true);
if (_unwindInfoMissing)
return UNW_STEP_END;
``````````
</details>
https://github.com/llvm/llvm-project/pull/103476
More information about the cfe-commits
mailing list