Skip to content

Commit c70fe97

Browse files
Abseil Teamcopybara-github
authored andcommitted
Reduce stack usage when unwinding without fixups
The existing code uses the same stack space regardless of whether fixups are performed. This commit avoids using the stack space in calls that statically bypass fixups, to reduce the potential of a stack overflow. PiperOrigin-RevId: 830610605 Change-Id: I06168e44e7199e10a606ff634e214ac9a8f9b872
1 parent 29d24c5 commit c70fe97

File tree

1 file changed

+31
-25
lines changed

1 file changed

+31
-25
lines changed

absl/debugging/stacktrace.cc

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include <algorithm>
4444
#include <atomic>
4545
#include <iterator>
46+
#include <type_traits>
4647

4748
#include "absl/base/attributes.h"
4849
#include "absl/base/config.h"
@@ -74,36 +75,37 @@ namespace {
7475
typedef int (*Unwinder)(void**, int*, int, int, const void*, int*);
7576
std::atomic<Unwinder> custom;
7677

77-
template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
78-
ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, uintptr_t* frames,
79-
int* sizes, size_t max_depth,
80-
int skip_count, const void* uc,
81-
int* min_dropped_frames,
82-
bool unwind_with_fixup = true) {
83-
static constexpr size_t kMaxStackElements = 128;
78+
constexpr size_t kMinPageSize = 4096;
8479

85-
static constexpr size_t kMinPageSize = 4096;
86-
static_assert(
87-
kMaxStackElements * (sizeof(*frames) + sizeof(*sizes)) < kMinPageSize / 2,
88-
"buffer size should be a fraction of a page to avoid stack overflows");
80+
struct FixupBuffer {
81+
static constexpr size_t kMaxStackElements = 128; // Can be reduced if needed
82+
uintptr_t frames[kMaxStackElements];
83+
int sizes[kMaxStackElements];
84+
};
85+
static_assert(std::is_trivially_default_constructible_v<FixupBuffer>);
86+
static_assert(sizeof(FixupBuffer) < kMinPageSize / 2,
87+
"buffer size should no larger than a small fraction of a page, "
88+
"to avoid stack overflows");
8989

90+
template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
91+
ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(
92+
void** result, uintptr_t* frames, int* sizes, size_t max_depth,
93+
int skip_count, const void* uc, int* min_dropped_frames,
94+
FixupBuffer* fixup_buffer /* if NULL, fixups are skipped */) {
9095
// Allocate a buffer dynamically, using the signal-safe allocator.
9196
static constexpr auto allocate = [](size_t num_bytes) -> void* {
9297
base_internal::InitSigSafeArena();
9398
return base_internal::LowLevelAlloc::AllocWithArena(
9499
num_bytes, base_internal::SigSafeArena());
95100
};
96101

97-
uintptr_t frames_stackbuf[kMaxStackElements];
98-
int sizes_stackbuf[kMaxStackElements];
99-
100102
// We only need to free the buffers if we allocated them with the signal-safe
101103
// allocator.
102104
bool must_free_frames = false;
103105
bool must_free_sizes = false;
104106

105-
unwind_with_fixup =
106-
unwind_with_fixup && internal_stacktrace::ShouldFixUpStack();
107+
bool unwind_with_fixup =
108+
fixup_buffer != nullptr && internal_stacktrace::ShouldFixUpStack();
107109

108110
#ifdef _WIN32
109111
if (unwind_with_fixup) {
@@ -122,17 +124,17 @@ ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, uintptr_t* frames,
122124
// here.
123125

124126
if (frames == nullptr) {
125-
if (max_depth <= std::size(frames_stackbuf)) {
126-
frames = frames_stackbuf;
127+
if (max_depth <= std::size(fixup_buffer->frames)) {
128+
frames = fixup_buffer->frames;
127129
} else {
128130
frames = static_cast<uintptr_t*>(allocate(max_depth * sizeof(*frames)));
129131
must_free_frames = true;
130132
}
131133
}
132134

133135
if (sizes == nullptr) {
134-
if (max_depth <= std::size(sizes_stackbuf)) {
135-
sizes = sizes_stackbuf;
136+
if (max_depth <= std::size(fixup_buffer->sizes)) {
137+
sizes = fixup_buffer->sizes;
136138
} else {
137139
sizes = static_cast<int*>(allocate(max_depth * sizeof(*sizes)));
138140
must_free_sizes = true;
@@ -182,42 +184,46 @@ ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, uintptr_t* frames,
182184
ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
183185
internal_stacktrace::GetStackFrames(void** result, uintptr_t* frames,
184186
int* sizes, int max_depth, int skip_count) {
187+
FixupBuffer fixup_stack_buf;
185188
return Unwind<true, false>(result, frames, sizes,
186189
static_cast<size_t>(max_depth), skip_count,
187-
nullptr, nullptr);
190+
nullptr, nullptr, &fixup_stack_buf);
188191
}
189192

190193
ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
191194
internal_stacktrace::GetStackFramesWithContext(void** result, uintptr_t* frames,
192195
int* sizes, int max_depth,
193196
int skip_count, const void* uc,
194197
int* min_dropped_frames) {
198+
FixupBuffer fixup_stack_buf;
195199
return Unwind<true, true>(result, frames, sizes,
196200
static_cast<size_t>(max_depth), skip_count, uc,
197-
min_dropped_frames);
201+
min_dropped_frames, &fixup_stack_buf);
198202
}
199203

200204
ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
201205
internal_stacktrace::GetStackTraceNoFixup(void** result, int max_depth,
202206
int skip_count) {
203207
return Unwind<false, false>(result, nullptr, nullptr,
204208
static_cast<size_t>(max_depth), skip_count,
205-
nullptr, nullptr, /*unwind_with_fixup=*/false);
209+
nullptr, nullptr, nullptr);
206210
}
207211

208212
ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackTrace(
209213
void** result, int max_depth, int skip_count) {
214+
FixupBuffer fixup_stack_buf;
210215
return Unwind<false, false>(result, nullptr, nullptr,
211216
static_cast<size_t>(max_depth), skip_count,
212-
nullptr, nullptr);
217+
nullptr, nullptr, &fixup_stack_buf);
213218
}
214219

215220
ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
216221
GetStackTraceWithContext(void** result, int max_depth, int skip_count,
217222
const void* uc, int* min_dropped_frames) {
223+
FixupBuffer fixup_stack_buf;
218224
return Unwind<false, true>(result, nullptr, nullptr,
219225
static_cast<size_t>(max_depth), skip_count, uc,
220-
min_dropped_frames);
226+
min_dropped_frames, &fixup_stack_buf);
221227
}
222228

223229
void SetStackUnwinder(Unwinder w) {

0 commit comments

Comments
 (0)