Prevent cross-module inlining of stack unwinder wrappers that adjust skip counts. `absl::DefaultStackUnwinder`, `CurrentStackTrace`, and `SavedStackTrace::CreateCurrent` increment `skip_count` assuming they occupy their own stack frame on the call stack, but were missing `ABSL_ATTRIBUTE_NOINLINE`. When LLVM commit `fc1afa6edce98a973ce2ce969c589da4f3aee975` enabled ThinLTO inlining of imported CFI jump table functions across translation units, these wrappers were inlined into their callers, causing stack unwinding to skip an extra caller frame. Add `ABSL_ATTRIBUTE_NOINLINE` (and `ABSL_ATTRIBUTE_NO_TAIL_CALL` / `ABSL_BLOCK_TAIL_CALL_OPTIMIZATION()`) to ensure their stack frames are preserved when calculating `skip_count`. PiperOrigin-RevId: 983379727 Change-Id: Ie6bdab705ebd1bf5c9acc1cc875e5ec535a84730
diff --git a/absl/debugging/stacktrace.cc b/absl/debugging/stacktrace.cc index 9689337..6dc366c 100644 --- a/absl/debugging/stacktrace.cc +++ b/absl/debugging/stacktrace.cc
@@ -161,8 +161,14 @@ custom.store(w, std::memory_order_release); } -int DefaultStackUnwinder(void** pcs, int* sizes, int depth, int skip, - const void* uc, int* min_dropped_frames) { +// As of LLVM commit go/compilers/fc1afa6edce98a973ce2ce969c589da4f3aee975, +// CFI functions are inlinable in the ThinLTO backend. As a result, these +// wrappers were inlined into their callers, causing stack unwinding to skip an +// extra caller frame. Prevent inlining to ensure their stack frames are +// preserved when calculating `skip_count`. +ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int DefaultStackUnwinder( + void** pcs, int* sizes, int depth, int skip, const void* uc, + int* min_dropped_frames) { skip++; // For this function decltype(&UnwindImpl<false, false>) f; if (sizes == nullptr) {