Skip to content

Commit 4123beb

Browse files
committed
fix memory consumption when using libbacktrace and speedup trace decoding
1 parent f0a9ba6 commit 4123beb

3 files changed

Lines changed: 45 additions & 21 deletions

File tree

include/boost/stacktrace/detail/libbacktrace_impls.hpp

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -60,30 +60,54 @@ inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int
6060
// Do nothing, just return.
6161
}
6262

63+
// Not async-signal-safe, so this method is not called from async-safe functions.
64+
//
65+
// This function is not async signal safe because:
66+
// * Dynamic initialization of a block-scope variable with static storage duration could lock a mutex
67+
// * No guarantees on `backtrace_create_state` function.
68+
//
69+
// Currently `backtrace_create_state` can not detect file name on Windows https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82543
70+
// That's why we provide a `prog_location` here.
71+
BOOST_SYMBOL_VISIBLE inline ::backtrace_state* construct_state(const program_location& prog_location) BOOST_NOEXCEPT {
72+
// [dcl.inline]: A static local variable in an inline function with external linkage always refers to the same object.
6373

64-
inline ::backtrace_state* construct_state(const program_location& prog_location) BOOST_NOEXCEPT {
65-
// Currently `backtrace_create_state` can not detect file name on Windows https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82543
66-
// That's why we provide a `prog_location` here.
67-
return ::backtrace_create_state(
68-
prog_location.name(), 0 /*thread-safe*/, boost::stacktrace::detail::libbacktrace_error_callback, 0
69-
);
70-
71-
// TODO: this does not seem to work well when this function is in .so:
72-
// Not async-signal-safe, so this method is not called from async-safe functions.
74+
// TODO: The most obvious solution:
75+
//
76+
//static ::backtrace_state* state = ::backtrace_create_state(
77+
// prog_location.name(),
78+
// 1, // allow safe concurrent usage of the same state
79+
// boost::stacktrace::detail::libbacktrace_error_callback,
80+
// 0 // pointer to data that will be passed to callback
81+
//);
82+
//
7383
//
74-
// This function is not async signal safe because:
75-
// * Dynamic initialization of a block-scope variable with static storage duration could lock a mutex
76-
// * No guarantees on `backtrace_create_state` function.
84+
// Unfortunately, that solution segfaults when `construct_state()` function is in .so file
85+
// and multiple threads concurrently work with state.
7786

78-
// [dcl.inline]: A static local variable in an inline function with external linkage always refers to the same object.
7987

80-
/*
81-
static ::backtrace_state* state = ::backtrace_create_state(
82-
0, 1 , boost::stacktrace::detail::libbacktrace_error_callback, 0
83-
);
88+
#ifndef BOOST_HAS_THREADS
89+
static
90+
#else
91+
92+
// Result of `construct_state()` invocation is not stored by the callers, so `thread_local`
93+
// gives a single `state` per thread and that state is not shared between threads in any way.
8494

95+
# ifndef BOOST_NO_CXX11_THREAD_LOCAL
96+
thread_local
97+
# elif defined(__GNUC__)
98+
static __thread
99+
# else
100+
/* just a local variable */
101+
# endif
102+
103+
#endif
104+
::backtrace_state* state = ::backtrace_create_state(
105+
prog_location.name(),
106+
0,
107+
boost::stacktrace::detail::libbacktrace_error_callback,
108+
0
109+
);
85110
return state;
86-
*/
87111
}
88112

89113
struct to_string_using_backtrace {

test/Jamfile.v2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,14 +220,14 @@ for local p in [ glob ../example/*.cpp ]
220220
test-suite stacktrace_torture
221221
:
222222
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) : torture_backtrace_ho ]
223-
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_ADDR2LINE $(AD2L_DEPS) : torture_addr2line_ho ]
223+
#[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_ADDR2LINE $(AD2L_DEPS) : torture_addr2line_ho ]
224224
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on $(WIND_DEPS) : torture_windbg_ho ]
225225
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_WINDBG_CACHED $(WICA_DEPS) : torture_windbg_cached_ho ]
226226
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on $(FORCE_SYMBOL_EXPORT) $(BASIC_DEPS) : torture_basic_ho ]
227227
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL $(BASIC_DEPS) : torture_basic_ho_empty ]
228228

229229
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_backtrace $(LINKSHARED_BT) : torture_backtrace_lib ]
230-
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_addr2line $(LINKSHARED_AD2L) : torture_addr2line_lib ]
230+
#[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_addr2line $(LINKSHARED_AD2L) : torture_addr2line_lib ]
231231
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_windbg $(LINKSHARED_WIND) : torture_windbg_lib ]
232232
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_windbg_cached $(LINKSHARED_WIND_CACHED) : torture_windbg_cached_lib ]
233233
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_basic $(LINKSHARED_BASIC) : torture_basic_lib ]

test/torture.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
int main() {
2020
int result = 0;
21-
for (unsigned i = 0; i < 10000; ++i) {
21+
for (unsigned i = 0; i < 10000000; ++i) {
2222
result += make_some_stacktrace1()[0].source_line();
2323
}
2424

0 commit comments

Comments
 (0)