Skip to content

Commit 342afd0

Browse files
Abseil Teamcopybara-github
authored andcommitted
Deduplicate stack trace implementations in stacktrace.cc
PiperOrigin-RevId: 786730361 Change-Id: I8184cd8a259570ff247077d7e3adaf430bd08ecc
1 parent 8a3065c commit 342afd0

2 files changed

Lines changed: 94 additions & 80 deletions

File tree

absl/debugging/stacktrace.cc

Lines changed: 41 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -97,54 +97,60 @@ std::atomic<Unwinder> custom;
9797

9898
template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
9999
ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, uintptr_t* frames,
100-
int* sizes, int max_depth,
100+
int* sizes, size_t max_depth,
101101
int skip_count, const void* uc,
102102
int* min_dropped_frames) {
103+
bool unwind_with_fixup = internal_stacktrace::ShouldFixUpStack();
104+
if (unwind_with_fixup) {
105+
if constexpr (kHaveAlloca) {
106+
// Some implementations of FixUpStack may need to be passed frame
107+
// information from Unwind, even if the caller doesn't need that
108+
// information. We allocate the necessary buffers for such implementations
109+
// here.
110+
if (frames == nullptr) {
111+
frames = static_cast<uintptr_t*>(alloca(max_depth * sizeof(*frames)));
112+
}
113+
if (sizes == nullptr) {
114+
sizes = static_cast<int*>(alloca(max_depth * sizeof(*sizes)));
115+
}
116+
}
117+
}
118+
103119
Unwinder g = custom.load(std::memory_order_acquire);
104-
int size;
120+
size_t size;
105121
// Add 1 to skip count for the unwinder function itself
106122
++skip_count;
107123
if (g != nullptr) {
108-
size = (*g)(result, sizes, max_depth, skip_count, uc, min_dropped_frames);
124+
size = static_cast<size_t>((*g)(result, sizes, static_cast<int>(max_depth),
125+
skip_count, uc, min_dropped_frames));
109126
// Frame pointers aren't returned by existing hooks, so clear them.
110127
if (frames != nullptr) {
111128
std::fill(frames, frames + size, uintptr_t());
112129
}
113130
} else {
114-
size = UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>(
115-
result, frames, sizes, max_depth, skip_count, uc, min_dropped_frames);
131+
size = static_cast<size_t>(
132+
unwind_with_fixup
133+
? UnwindImpl<true, IS_WITH_CONTEXT>(
134+
result, frames, sizes, static_cast<int>(max_depth),
135+
skip_count, uc, min_dropped_frames)
136+
: UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>(
137+
result, frames, sizes, static_cast<int>(max_depth),
138+
skip_count, uc, min_dropped_frames));
139+
}
140+
if (unwind_with_fixup) {
141+
internal_stacktrace::FixUpStack(result, frames, sizes, max_depth, size);
116142
}
117143
ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
118-
return size;
144+
return static_cast<int>(size);
119145
}
120146

121147
} // anonymous namespace
122148

123149
ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
124150
internal_stacktrace::GetStackFrames(void** result, uintptr_t* frames,
125151
int* sizes, int max_depth, int skip_count) {
126-
if (internal_stacktrace::ShouldFixUpStack()) {
127-
if constexpr (kHaveAlloca) {
128-
// Some implementations of FixUpStack may need to be passed frame
129-
// information from Unwind, even if the caller doesn't need that
130-
// information. We allocate the necessary buffers for such implementations
131-
// here.
132-
const size_t nmax = static_cast<size_t>(max_depth);
133-
if (frames == nullptr) {
134-
frames = static_cast<uintptr_t*>(alloca(nmax * sizeof(*frames)));
135-
}
136-
if (sizes == nullptr) {
137-
sizes = static_cast<int*>(alloca(nmax * sizeof(*sizes)));
138-
}
139-
}
140-
size_t depth = static_cast<size_t>(Unwind<true, true>(
141-
result, frames, sizes, max_depth, skip_count, nullptr, nullptr));
142-
internal_stacktrace::FixUpStack(result, frames, sizes,
143-
static_cast<size_t>(max_depth), depth);
144-
return static_cast<int>(depth);
145-
}
146-
147-
return Unwind<true, false>(result, frames, sizes, max_depth, skip_count,
152+
return Unwind<true, false>(result, frames, sizes,
153+
static_cast<size_t>(max_depth), skip_count,
148154
nullptr, nullptr);
149155
}
150156

@@ -153,69 +159,24 @@ internal_stacktrace::GetStackFramesWithContext(void** result, uintptr_t* frames,
153159
int* sizes, int max_depth,
154160
int skip_count, const void* uc,
155161
int* min_dropped_frames) {
156-
if (internal_stacktrace::ShouldFixUpStack()) {
157-
if constexpr (kHaveAlloca) {
158-
// Some implementations of FixUpStack may need to be passed frame
159-
// information from Unwind, even if the caller doesn't need that
160-
// information. We allocate the necessary buffers for such implementations
161-
// here.
162-
const size_t nmax = static_cast<size_t>(max_depth);
163-
if (frames == nullptr) {
164-
frames = static_cast<uintptr_t*>(alloca(nmax * sizeof(*frames)));
165-
}
166-
if (sizes == nullptr) {
167-
sizes = static_cast<int*>(alloca(nmax * sizeof(*sizes)));
168-
}
169-
}
170-
size_t depth = static_cast<size_t>(Unwind<true, true>(
171-
result, frames, sizes, max_depth, skip_count, uc, min_dropped_frames));
172-
internal_stacktrace::FixUpStack(result, frames, sizes,
173-
static_cast<size_t>(max_depth), depth);
174-
return static_cast<int>(depth);
175-
}
176-
177-
return Unwind<true, true>(result, frames, sizes, max_depth, skip_count, uc,
162+
return Unwind<true, true>(result, frames, sizes,
163+
static_cast<size_t>(max_depth), skip_count, uc,
178164
min_dropped_frames);
179165
}
180166

181167
ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackTrace(
182168
void** result, int max_depth, int skip_count) {
183-
if (internal_stacktrace::ShouldFixUpStack()) {
184-
if constexpr (kHaveAlloca) {
185-
const size_t nmax = static_cast<size_t>(max_depth);
186-
uintptr_t* frames =
187-
static_cast<uintptr_t*>(alloca(nmax * sizeof(*frames)));
188-
int* sizes = static_cast<int*>(alloca(nmax * sizeof(*sizes)));
189-
size_t depth = static_cast<size_t>(Unwind<true, false>(
190-
result, frames, sizes, max_depth, skip_count, nullptr, nullptr));
191-
internal_stacktrace::FixUpStack(result, frames, sizes, nmax, depth);
192-
return static_cast<int>(depth);
193-
}
194-
}
195-
196-
return Unwind<false, false>(result, nullptr, nullptr, max_depth, skip_count,
169+
return Unwind<false, false>(result, nullptr, nullptr,
170+
static_cast<size_t>(max_depth), skip_count,
197171
nullptr, nullptr);
198172
}
199173

200174
ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
201175
GetStackTraceWithContext(void** result, int max_depth, int skip_count,
202176
const void* uc, int* min_dropped_frames) {
203-
if (internal_stacktrace::ShouldFixUpStack()) {
204-
if constexpr (kHaveAlloca) {
205-
const size_t nmax = static_cast<size_t>(max_depth);
206-
uintptr_t* frames =
207-
static_cast<uintptr_t*>(alloca(nmax * sizeof(*frames)));
208-
int* sizes = static_cast<int*>(alloca(nmax * sizeof(*sizes)));
209-
size_t depth = static_cast<size_t>(
210-
Unwind<true, true>(result, frames, sizes, max_depth, skip_count, uc,
211-
min_dropped_frames));
212-
internal_stacktrace::FixUpStack(result, frames, sizes, nmax, depth);
213-
return static_cast<int>(depth);
214-
}
215-
}
216-
217-
return Unwind<false, true>(result, nullptr, nullptr, max_depth, skip_count,
218-
uc, min_dropped_frames);
177+
return Unwind<false, true>(result, nullptr, nullptr,
178+
static_cast<size_t>(max_depth), skip_count, uc,
179+
min_dropped_frames);
219180
}
220181

221182
void SetStackUnwinder(Unwinder w) {

absl/debugging/stacktrace_test.cc

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,59 @@ ABSL_ATTRIBUTE_NOINLINE static void FixupNoFixupEquivalenceNoInline() {
218218

219219
TEST(StackTrace, FixupNoFixupEquivalence) { FixupNoFixupEquivalenceNoInline(); }
220220

221+
TEST(StackTrace, CustomUnwinderPerformsFixup) {
222+
#if ABSL_HAVE_ATTRIBUTE_WEAK
223+
// This test is known not to pass on MSVC (due to weak symbols)
224+
225+
constexpr int kSkip = 1; // Skip our own frame, whose return PCs won't match
226+
constexpr auto kStackCount = 1;
227+
228+
absl::SetStackUnwinder(absl::DefaultStackUnwinder);
229+
const Cleanup restore_state([enable_fixup = g_enable_fixup,
230+
fixup_calls = g_fixup_calls,
231+
should_fixup_calls = g_should_fixup_calls]() {
232+
absl::SetStackUnwinder(nullptr);
233+
g_enable_fixup = enable_fixup;
234+
g_fixup_calls = fixup_calls;
235+
g_should_fixup_calls = should_fixup_calls;
236+
});
237+
238+
StackTrace trace;
239+
240+
g_enable_fixup = true;
241+
g_should_fixup_calls = 0;
242+
g_fixup_calls = 0;
243+
absl::GetStackTrace(trace.result, kSkip, kStackCount);
244+
EXPECT_GT(g_should_fixup_calls, 0);
245+
EXPECT_GT(g_fixup_calls, 0);
246+
247+
g_enable_fixup = true;
248+
g_should_fixup_calls = 0;
249+
g_fixup_calls = 0;
250+
absl::GetStackFrames(trace.result, trace.sizes, kSkip, kStackCount);
251+
EXPECT_GT(g_should_fixup_calls, 0);
252+
EXPECT_GT(g_fixup_calls, 0);
253+
254+
g_enable_fixup = true;
255+
g_should_fixup_calls = 0;
256+
g_fixup_calls = 0;
257+
absl::GetStackTraceWithContext(trace.result, kSkip, kStackCount, nullptr,
258+
nullptr);
259+
EXPECT_GT(g_should_fixup_calls, 0);
260+
EXPECT_GT(g_fixup_calls, 0);
261+
262+
g_enable_fixup = true;
263+
g_should_fixup_calls = 0;
264+
g_fixup_calls = 0;
265+
absl::GetStackFramesWithContext(trace.result, trace.sizes, kSkip, kStackCount,
266+
nullptr, nullptr);
267+
EXPECT_GT(g_should_fixup_calls, 0);
268+
EXPECT_GT(g_fixup_calls, 0);
269+
#else
270+
GTEST_SKIP() << "Need weak symbol support";
271+
#endif
272+
}
273+
221274
#if ABSL_HAVE_BUILTIN(__builtin_frame_address)
222275
struct FrameInfo {
223276
const void* return_address;

0 commit comments

Comments
 (0)