Commit 2b042424 by Abseil Team Committed by Copybara-Service

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
parent 0f4133aa
...@@ -94,16 +94,21 @@ static void **NextStackFrame(void **old_frame_pointer, const void *uc) { ...@@ -94,16 +94,21 @@ static void **NextStackFrame(void **old_frame_pointer, const void *uc) {
void **const pre_signal_frame_pointer = void **const pre_signal_frame_pointer =
reinterpret_cast<void **>(ucv->uc_mcontext.regs[29]); 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 // 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. // prevent "double fault" in case we hit the first fault due to e.g.
// stack corruption. // stack corruption.
if (!absl::debugging_internal::AddressIsReadable( if (!absl::debugging_internal::AddressIsReadable(
pre_signal_frame_pointer)) new_frame_pointer))
return nullptr; 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 // Skip frame size check if we return from a signal. We may be using a
// an alternate stack for signals. // an alternate stack for signals.
check_frame_size = false; check_frame_size = false;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment