diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2020-02-27 12:07:42 +0100 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2020-02-27 16:02:11 +0100 |
commit | 853a058ca6b75b0fb14e232911eb9f9553574736 (patch) | |
tree | e8efa89aae59d92be759d421c68dfb3cad9effc6 /sal | |
parent | e8c07076689d593b9d2863d166b1933ecb6f480a (diff) |
avoid memory leak in win32 sal::backtrace_get()
Running a presentation with OpenGL transitions with Skia+Vulkan
as the VCL drawing very quickly runs out of memory in dbgutil
builds. The trigger is svl/source/notify/lstner.cxx calling
sal::backtrace_get() quite often. And that function calls
SymInitialize() repeatedly even though its docs say not to do it,
and that is also actually not necessary for CaptureStackBackTrace(),
only for the symbol resolving Sym* functions.
It actually still eventually aborts if called often enough,
but this way it is triggered only by printing the backtrace and
not just getting it.
I have no idea why the problem is triggered only in these rather
specific circumstances, e.g. Skia+raster seems to be fine.
Also avoid the needless copy&paste while I'm at it.
Change-Id: I50f9e0689b9b9b10bf54308db654aed6433085db
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89626
Tested-by: Jenkins
Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
Diffstat (limited to 'sal')
-rw-r--r-- | sal/osl/unx/backtraceapi.cxx | 23 | ||||
-rw-r--r-- | sal/osl/w32/backtrace.cxx | 54 |
2 files changed, 14 insertions, 63 deletions
diff --git a/sal/osl/unx/backtraceapi.cxx b/sal/osl/unx/backtraceapi.cxx index ae1670c30b92..93ca94da5ff2 100644 --- a/sal/osl/unx/backtraceapi.cxx +++ b/sal/osl/unx/backtraceapi.cxx @@ -36,27 +36,8 @@ struct FreeGuard { } OUString osl::detail::backtraceAsString(sal_uInt32 maxDepth) { - assert(maxDepth != 0); - auto const maxInt = static_cast<unsigned int>( - std::numeric_limits<int>::max()); - if (maxDepth > maxInt) { - maxDepth = static_cast<sal_uInt32>(maxInt); - } - auto b1 = std::make_unique<void *[]>(maxDepth); - int n = backtrace(b1.get(), static_cast<int>(maxDepth)); - FreeGuard b2(backtrace_symbols(b1.get(), n)); - b1.reset(); - if (b2.buffer == nullptr) { - return OUString(); - } - OUStringBuffer b3; - for (int i = 0; i != n; ++i) { - if (i != 0) { - b3.append("\n"); - } - b3.append(o3tl::runtimeToOUString(b2.buffer[i])); - } - return b3.makeStringAndClear(); + std::unique_ptr<sal::BacktraceState> backtrace = sal::backtrace_get( maxDepth ); + return sal::backtrace_to_string( backtrace.get()); } std::unique_ptr<sal::BacktraceState> sal::backtrace_get(sal_uInt32 maxDepth) diff --git a/sal/osl/w32/backtrace.cxx b/sal/osl/w32/backtrace.cxx index 9e31616eaaff..fab3c5043a60 100644 --- a/sal/osl/w32/backtrace.cxx +++ b/sal/osl/w32/backtrace.cxx @@ -37,42 +37,8 @@ template<typename T> T clampToULONG(T n) { OUString osl::detail::backtraceAsString(sal_uInt32 maxDepth) { - assert(maxDepth != 0); - maxDepth = clampToULONG(maxDepth); - - OUStringBuffer aBuf; - - HANDLE hProcess = GetCurrentProcess(); - SymInitialize( hProcess, nullptr, true ); - - std::unique_ptr<void*[]> aStack(new void*[ maxDepth ]); - // https://msdn.microsoft.com/en-us/library/windows/desktop/bb204633.aspx - // "CaptureStackBackTrace function" claims that you "can capture up to - // MAXUSHORT frames", and on Windows Server 2003 and Windows XP it even - // "must be less than 63", but assume that a too large input value is - // clamped internally, instead of resulting in an error: - sal_uInt32 nFrames = CaptureStackBackTrace( 0, static_cast<ULONG>(maxDepth), aStack.get(), nullptr ); - - SYMBOL_INFO * pSymbol; - pSymbol = static_cast<SYMBOL_INFO *>(calloc( sizeof( SYMBOL_INFO ) + 1024 * sizeof( char ), 1 )); - assert(pSymbol); - pSymbol->MaxNameLen = 1024 - 1; - pSymbol->SizeOfStruct = sizeof( SYMBOL_INFO ); - - for( sal_uInt32 i = 0; i < nFrames; i++ ) - { - SymFromAddr( hProcess, reinterpret_cast<DWORD64>(aStack[ i ]), nullptr, pSymbol ); - aBuf.append( static_cast<sal_Int32>(nFrames - i - 1) ); - aBuf.append( ": " ); - aBuf.appendAscii( pSymbol->Name ); - aBuf.append( " - 0x" ); - aBuf.append( static_cast<sal_Int64>(pSymbol->Address), 16 ); - aBuf.append( "\n" ); - } - - free( pSymbol ); - - return aBuf.makeStringAndClear(); + std::unique_ptr<sal::BacktraceState> backtrace = sal::backtrace_get( maxDepth ); + return sal::backtrace_to_string( backtrace.get()); } std::unique_ptr<sal::BacktraceState> sal::backtrace_get(sal_uInt32 maxDepth) @@ -80,9 +46,6 @@ std::unique_ptr<sal::BacktraceState> sal::backtrace_get(sal_uInt32 maxDepth) assert(maxDepth != 0); maxDepth = clampToULONG(maxDepth); - HANDLE hProcess = GetCurrentProcess(); - SymInitialize( hProcess, nullptr, true ); - auto pStack = new void *[maxDepth]; // https://msdn.microsoft.com/en-us/library/windows/desktop/bb204633.aspx // "CaptureStackBackTrace function" claims that you "can capture up to @@ -96,16 +59,23 @@ std::unique_ptr<sal::BacktraceState> sal::backtrace_get(sal_uInt32 maxDepth) OUString sal::backtrace_to_string(BacktraceState* backtraceState) { - OUStringBuffer aBuf; - + HANDLE hProcess = GetCurrentProcess(); + // https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-syminitialize + // says to not initialize more than once. This still leaks for some + // reason if called often enough. + static bool needsInit = true; + if( needsInit ) + SymInitialize( hProcess, nullptr, true ); + else + SymRefreshModuleList( hProcess ); SYMBOL_INFO * pSymbol; pSymbol = static_cast<SYMBOL_INFO *>(calloc( sizeof( SYMBOL_INFO ) + 1024 * sizeof( char ), 1 )); assert(pSymbol); pSymbol->MaxNameLen = 1024 - 1; pSymbol->SizeOfStruct = sizeof( SYMBOL_INFO ); - HANDLE hProcess = GetCurrentProcess(); auto nFrames = backtraceState->nDepth; + OUStringBuffer aBuf; for( int i = 0; i < nFrames; i++ ) { SymFromAddr( hProcess, reinterpret_cast<DWORD64>(backtraceState->buffer[ i ]), nullptr, pSymbol ); |