diff options
author | igorbalduev <igorbalduev@yandex-team.com> | 2023-12-06 22:36:35 +0300 |
---|---|---|
committer | igorbalduev <igorbalduev@yandex-team.com> | 2023-12-07 00:10:15 +0300 |
commit | e0419f0f4d03f87749ac004ded90a9a3604455e3 (patch) | |
tree | 6e97a2ded581b899ec59002c42b19c39e0f196a0 /library/cpp | |
parent | 50525833ed09067aa2f03551c08a54f7a839c2b7 (diff) | |
download | ydb-e0419f0f4d03f87749ac004ded90a9a3604455e3.tar.gz |
Support for single-threaded backtrace_state
Обнаружилось, что при использовании *libbacktrace* в многопоточном режиме приложение течёт по памяти. Пофиксили утечки мьютексом, но т.к. теперь *libbacktrace* в нашем коде фактически используется в один поток, имеет смысл использовать его с соответствующими опциями в `backtrace_state`.
Добавил сбоку к существующему коду `unsafe`-версию `ResolveBacktrace`.
Diffstat (limited to 'library/cpp')
-rw-r--r-- | library/cpp/dwarf_backtrace/backtrace.cpp | 67 | ||||
-rw-r--r-- | library/cpp/dwarf_backtrace/backtrace.h | 6 |
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); } |