diff options
author | Abseil Team <absl-team@google.com> | 2023-06-09 10:10:46 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-06-09 10:11:36 -0700 |
commit | 2b042424db44e9614d3c100832dff1a54f37b351 (patch) | |
tree | 0af078d4c53ae85bc618562c310871327482737c /absl/debugging | |
parent | 0f4133aacfa2ebc84c76f69e6ab02ce58603072f (diff) |
Fix unwinding through nested signal frames on aarch64.
This fixes an endless loop in the absl Arm stack unwinder where encountering a
second signal return trampoline (as one has in nested signal frames), would restart
unwinding at the outermost signal, resulting in an endless loop.
This does not change any behavior in the non-nested signal case, so I believe
it is safe for any stack that hasn't encountered this bug already.
I would love to test this beyond the absl unwinding test cases and the
fingerprint_test included here, but I'm at a loss for other test cases.
PiperOrigin-RevId: 539113007
Change-Id: I10037f9fa77b45cc4db61f89b9c6380ec3529113
Diffstat (limited to 'absl/debugging')
-rw-r--r-- | absl/debugging/internal/stacktrace_aarch64-inl.inc | 13 |
1 files changed, 9 insertions, 4 deletions
diff --git a/absl/debugging/internal/stacktrace_aarch64-inl.inc b/absl/debugging/internal/stacktrace_aarch64-inl.inc index b66beba2..520e9a84 100644 --- a/absl/debugging/internal/stacktrace_aarch64-inl.inc +++ b/absl/debugging/internal/stacktrace_aarch64-inl.inc @@ -94,16 +94,21 @@ static void **NextStackFrame(void **old_frame_pointer, const void *uc) { void **const pre_signal_frame_pointer = reinterpret_cast<void **>(ucv->uc_mcontext.regs[29]); + // The most recent signal always needs special handling to find the frame + // pointer, but a nested signal does not. If pre_signal_frame_pointer is + // earlier in the stack than the old_frame_pointer, then use it. If it is + // later, then we have already unwound through it and it needs no special + // handling. + if (pre_signal_frame_pointer >= old_frame_pointer) { + new_frame_pointer = pre_signal_frame_pointer; + } // Check that alleged frame pointer is actually readable. This is to // prevent "double fault" in case we hit the first fault due to e.g. // stack corruption. if (!absl::debugging_internal::AddressIsReadable( - pre_signal_frame_pointer)) + new_frame_pointer)) return nullptr; - // Alleged frame pointer is readable, use it for further unwinding. - new_frame_pointer = pre_signal_frame_pointer; - // Skip frame size check if we return from a signal. We may be using a // an alternate stack for signals. check_frame_size = false; |