aboutsummaryrefslogtreecommitdiffstats
path: root/library
diff options
context:
space:
mode:
authorigorbalduev <igorbalduev@yandex-team.com>2023-12-06 22:36:35 +0300
committerigorbalduev <igorbalduev@yandex-team.com>2023-12-07 00:10:15 +0300
commite0419f0f4d03f87749ac004ded90a9a3604455e3 (patch)
tree6e97a2ded581b899ec59002c42b19c39e0f196a0 /library
parent50525833ed09067aa2f03551c08a54f7a839c2b7 (diff)
downloadydb-e0419f0f4d03f87749ac004ded90a9a3604455e3.tar.gz
Support for single-threaded backtrace_state
Обнаружилось, что при использовании *libbacktrace* в многопоточном режиме приложение течёт по памяти. Пофиксили утечки мьютексом, но т.к. теперь *libbacktrace* в нашем коде фактически используется в один поток, имеет смысл использовать его с соответствующими опциями в `backtrace_state`. Добавил сбоку к существующему коду `unsafe`-версию `ResolveBacktrace`.
Diffstat (limited to 'library')
-rw-r--r--library/cpp/dwarf_backtrace/backtrace.cpp67
-rw-r--r--library/cpp/dwarf_backtrace/backtrace.h6
2 files changed, 50 insertions, 23 deletions
diff --git a/library/cpp/dwarf_backtrace/backtrace.cpp b/library/cpp/dwarf_backtrace/backtrace.cpp
index a955d07249..7dcfd12ea7 100644
--- a/library/cpp/dwarf_backtrace/backtrace.cpp
+++ b/library/cpp/dwarf_backtrace/backtrace.cpp
@@ -6,6 +6,8 @@
#include <util/system/type_name.h>
#include <util/system/execpath.h>
+#include <mutex>
+
namespace NDwarf {
namespace {
struct TContext {
@@ -31,32 +33,51 @@ namespace NDwarf {
};
return static_cast<int>(context->Callback(lineInfo));
}
- }
- TMaybe<TError> ResolveBacktrace(TArrayRef<const void* const> backtrace, TCallback callback) {
- TContext context{.Callback = callback};
- // Intentionally never freed (see https://a.yandex-team.ru/arc/trunk/arcadia/contrib/libs/backtrace/backtrace.h?rev=6789902#L80).
- static auto* state = backtrace_create_state(
- GetPersistentExecPath().c_str(),
- 1 /* threaded */,
- HandleLibBacktraceError,
- &context /* data for the error callback */
- );
- if (nullptr == state) {
- static const auto initError = context.Error;
- return initError;
- }
- for (const void* address : backtrace) {
- int status = backtrace_pcinfo(
- state,
- reinterpret_cast<uintptr_t>(address) - 1, // last byte of the call instruction
- HandleLibBacktraceFrame,
+ auto CreateBacktraceState(TContext& context, bool threaded) {
+ return backtrace_create_state(
+ GetPersistentExecPath().c_str(),
+ static_cast<int>(threaded),
HandleLibBacktraceError,
- &context /* data for both callbacks */);
- if (0 != status) {
- break;
+ &context /* data for the error callback */
+ );
+ }
+
+ TMaybe<TError> ResolveBacktraceImpl(backtrace_state* state, TArrayRef<const void* const> backtrace, TContext& context) {
+ if (nullptr == state) {
+ static const auto initError = context.Error;
+ return initError;
}
+ for (const void* address : backtrace) {
+ int status = backtrace_pcinfo(
+ state,
+ reinterpret_cast<uintptr_t>(address) - 1, // last byte of the call instruction
+ HandleLibBacktraceFrame,
+ HandleLibBacktraceError,
+ &context /* data for both callbacks */);
+ if (0 != status) {
+ break;
+ }
+ }
+ return context.Error;
}
- return context.Error;
+ }
+
+ TMaybe<TError> ResolveBacktrace(TArrayRef<const void* const> backtrace, TCallback callback) {
+ TContext context{.Callback = callback};
+ // Intentionally never freed (see the documentation to `backtrace_create_state`).
+ static auto* state{CreateBacktraceState(context, true /* enable threading support */)};
+
+ return ResolveBacktraceImpl(state, backtrace, context);
+ }
+
+ TMaybe<TError> ResolveBacktraceLocked(TArrayRef<const void* const> backtrace, TCallback callback) {
+ TContext context{.Callback = callback};
+ // Intentionally never freed (see the documentation to `backtrace_create_state`).
+ static auto* state{CreateBacktraceState(context, false /* disable threading support */)};
+ static std::mutex mutex;
+
+ const std::lock_guard lock{mutex};
+ return ResolveBacktraceImpl(state, backtrace, context);
}
}
diff --git a/library/cpp/dwarf_backtrace/backtrace.h b/library/cpp/dwarf_backtrace/backtrace.h
index 62ec36dba5..eeda4d40d9 100644
--- a/library/cpp/dwarf_backtrace/backtrace.h
+++ b/library/cpp/dwarf_backtrace/backtrace.h
@@ -33,4 +33,10 @@ namespace NDwarf {
// Stops execution if the callback returns `EResolving::Break`.
[[nodiscard]] TMaybe<TError> ResolveBacktrace(TArrayRef<const void* const> backtrace, TCallback callback);
+ // Same as `ResolveBacktrace` but uses a separate single-threaded `backtrace_state` protected by a static mutex.
+ //
+ // libbacktrace may leak memory when used concurrently even with the `threaded` option set to 1,
+ // which is explicitly stated in its source code (contrib/libs/backtrace/dwarf.c:dwarf_lookup_pc,
+ // contrib/libs/backtrace/fileline.c:fileline_initialize) and confirmed in MAPSBKOFCT-1959.
+ [[nodiscard]] TMaybe<TError> ResolveBacktraceLocked(TArrayRef<const void* const> backtrace, TCallback callback);
}