mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 12:07:05 +08:00
Fix a corner case in the aarch64 unwinder
In case of two nested back-to-back signals (such as what happens in NestedSignal test) we could end up erroneously using the frame pointer from ucontext_t twice, leading to premature backtrace termination. In the situation where this happens, the call stack looks like #0 <unwinder frames> #1 SigUsr2Handler #2 __kernel_rt_sigreturn #3 raise #4 SigUsr1Handler #5 __kernel_rt_sigreturn #6 raise #7 RaiseSignal ... When unwinding from #2, we get the fp value from the ucontext (as we should). However, because raise does not modify the fp and because SigUsr1Handler is also a signal handler, when we try to unwind from #4 (#3 is skipped), NextStackFrame ends up looking at the ucontext fp again, and comparing it with the previous (identical) FP value. Non-strict equality accepts this as a valid frame, but the unwinder later bails out due to a zero-sized frame. Using a strict equality causes NextStackFrame to reject the ucontext fp and use the FP from FP chain instead. This causes us to skip a few more frames, but at least we continue to unwind instead of giving up. In this case, the computed backtrace skips functions #3, #4 and #6. PiperOrigin-RevId: 804308754 Change-Id: I5d43e6bea80e4abff1075ada03782ae11c599161
This commit is contained in:
committed by
Copybara-Service
parent
7fc86c6786
commit
26c9126028
@@ -123,7 +123,7 @@ static void **NextStackFrame(void **old_frame_pointer, const void *uc,
|
||||
// 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) {
|
||||
if (pre_signal_frame_pointer > old_frame_pointer) {
|
||||
new_frame_pointer = pre_signal_frame_pointer;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user