diff options
-rw-r--r-- | editeng/source/editeng/impedit5.cxx | 2 | ||||
-rw-r--r-- | include/sal/backtrace.hxx | 44 | ||||
-rw-r--r-- | include/svl/lstner.hxx | 4 | ||||
-rw-r--r-- | sal/osl/unx/backtraceapi.cxx | 30 | ||||
-rw-r--r-- | sal/osl/w32/backtrace.cxx | 51 | ||||
-rw-r--r-- | sal/util/sal.map | 6 | ||||
-rw-r--r-- | sd/source/ui/sidebar/MasterPageObserver.cxx | 4 | ||||
-rw-r--r-- | svl/source/notify/lstner.cxx | 47 | ||||
-rw-r--r-- | svx/source/unodraw/unoshape.cxx | 15 | ||||
-rw-r--r-- | sw/source/core/layout/frmtool.cxx | 9 | ||||
-rw-r--r-- | sw/source/uibase/utlui/navipi.cxx | 3 |
11 files changed, 194 insertions, 21 deletions
diff --git a/editeng/source/editeng/impedit5.cxx b/editeng/source/editeng/impedit5.cxx index 5ec8e65e32d6..5ba3549c9360 100644 --- a/editeng/source/editeng/impedit5.cxx +++ b/editeng/source/editeng/impedit5.cxx @@ -92,7 +92,7 @@ void ImpEditEngine::SetStyleSheet( sal_Int32 nPara, SfxStyleSheet* pStyle ) EndListening( *pCurStyle ); pNode->SetStyleSheet( pStyle, aStatus.UseCharAttribs() ); if ( pStyle ) - StartListening( *pStyle ); + StartListening( *pStyle, true ); ParaAttribsChanged( pNode ); } FormatAndUpdate(); diff --git a/include/sal/backtrace.hxx b/include/sal/backtrace.hxx new file mode 100644 index 000000000000..2c854e102eef --- /dev/null +++ b/include/sal/backtrace.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_SAL_BACKTRACE_HXX +#define INCLUDED_SAL_BACKTRACE_HXX + +#include <sal/config.h> +#include <sal/saldllapi.h> +#include <sal/types.h> +#include <rtl/ustring.hxx> +#include <memory> + +/// @cond INTERNAL +/** + Two stage API for recording and then later decoding stack backtraces. + Useful for debugging facilities where we are only interested in decoding + a small handful of recorded stack traces. + + @param backtraceDepth value indicating the maximum backtrace depth; must be > 0 +*/ +#if defined LIBO_INTERNAL_ONLY + +struct BacktraceState { + void** buffer; + int nDepth; +}; + +SAL_DLLPUBLIC std::unique_ptr<BacktraceState> SAL_CALL sal_backtrace_get( + sal_uInt32 backtraceDepth); + +SAL_DLLPUBLIC OUString SAL_CALL sal_backtrace_to_string( + BacktraceState* backtraceState); + +#endif + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/svl/lstner.hxx b/include/svl/lstner.hxx index 527a13baa834..ad79698728cb 100644 --- a/include/svl/lstner.hxx +++ b/include/svl/lstner.hxx @@ -39,8 +39,8 @@ public: SfxListener( const SfxListener &rCopy ); virtual ~SfxListener() COVERITY_NOEXCEPT_FALSE; - void StartListening( SfxBroadcaster& rBroadcaster, bool bPreventDups = false ); - void EndListening( SfxBroadcaster& rBroadcaster, bool bAllDups = false ); + void StartListening( SfxBroadcaster& rBroadcaster, bool bPreventDuplicates = false ); + void EndListening( SfxBroadcaster& rBroadcaster, bool bRemoveAllDuplicates = false ); void EndListeningAll(); bool IsListening( SfxBroadcaster& rBroadcaster ) const; diff --git a/sal/osl/unx/backtraceapi.cxx b/sal/osl/unx/backtraceapi.cxx index 91be8d5d40c4..4838474be36c 100644 --- a/sal/osl/unx/backtraceapi.cxx +++ b/sal/osl/unx/backtraceapi.cxx @@ -18,6 +18,7 @@ #include <rtl/ustrbuf.hxx> #include <rtl/ustring.hxx> #include <sal/types.h> +#include <sal/backtrace.hxx> #include "backtrace.h" #include "backtraceasstring.hxx" @@ -58,4 +59,33 @@ OUString osl::detail::backtraceAsString(sal_uInt32 maxDepth) { return b3.makeStringAndClear(); } +std::unique_ptr<BacktraceState> sal_backtrace_get(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 = new void *[maxDepth]; + int n = backtrace(b1, static_cast<int>(maxDepth)); + return std::unique_ptr<BacktraceState>(new BacktraceState{ b1, n }); +} + +OUString sal_backtrace_to_string(BacktraceState* backtraceState) +{ + FreeGuard b2(backtrace_symbols(backtraceState->buffer, backtraceState->nDepth)); + if (b2.buffer == nullptr) { + return OUString(); + } + OUStringBuffer b3; + for (int i = 0; i != backtraceState->nDepth; ++i) { + if (i != 0) { + b3.append("\n"); + } + b3.append(o3tl::runtimeToOUString(b2.buffer[i])); + } + return b3.makeStringAndClear(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/backtrace.cxx b/sal/osl/w32/backtrace.cxx index a8a4cf445e9f..230adca4a2f8 100644 --- a/sal/osl/w32/backtrace.cxx +++ b/sal/osl/w32/backtrace.cxx @@ -19,6 +19,7 @@ #include <DbgHelp.h> #include <rtl/ustrbuf.hxx> +#include <sal/backtrace.hxx> #include "backtraceasstring.hxx" @@ -64,4 +65,54 @@ OUString osl::detail::backtraceAsString(sal_uInt32 maxDepth) return aBuf.makeStringAndClear(); } +std::unique_ptr<BacktraceState> sal_backtrace_get(sal_uInt32 maxDepth) +{ + assert(maxDepth != 0); + auto const maxUlong = std::numeric_limits<ULONG>::max(); + if (maxDepth > maxUlong) { + maxDepth = static_cast<sal_uInt32>(maxUlong); + } + + 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 + // 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: + int nFrames = CaptureStackBackTrace( 0, static_cast<ULONG>(maxDepth), pStack, nullptr ); + + return std::unique_ptr<BacktraceState>(new BacktraceState{ pStack, nFrames }); +} + +OUString sal_backtrace_to_string(BacktraceState* backtraceState) +{ + OUStringBuffer aBuf; + + SYMBOL_INFO * pSymbol; + pSymbol = static_cast<SYMBOL_INFO *>(calloc( sizeof( SYMBOL_INFO ) + 1024 * sizeof( char ), 1 )); + pSymbol->MaxNameLen = 1024 - 1; + pSymbol->SizeOfStruct = sizeof( SYMBOL_INFO ); + HANDLE hProcess = GetCurrentProcess(); + + auto nFrames = backtraceState->nDepth; + for( int i = 0; i < nFrames; i++ ) + { + SymFromAddr( hProcess, reinterpret_cast<DWORD64>(backtraceState->buffer[ i ]), nullptr, pSymbol ); + aBuf.append( (sal_Int32)(nFrames - i - 1) ); + aBuf.append( ": " ); + aBuf.appendAscii( pSymbol->Name ); + aBuf.append( " - 0x" ); + aBuf.append( (sal_Int64)pSymbol->Address, 16 ); + aBuf.append( "\n" ); + } + + free( pSymbol ); + + return aBuf.makeStringAndClear(); +} + + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/util/sal.map b/sal/util/sal.map index b04487e4d548..e9195a1434f8 100644 --- a/sal/util/sal.map +++ b/sal/util/sal.map @@ -733,6 +733,12 @@ PRIVATE_1.3 { # LibreOffice 5.4 sal_detail_log_report; } PRIVATE_1.2; +PRIVATE_1.4 { # LibreOffice 6.0 + global: + _Z17sal_backtrace_getj; + _Z23sal_backtrace_to_stringP14BacktraceState; +} PRIVATE_1.3; + PRIVATE_textenc.1 { # LibreOffice 3.6 global: _ZN3sal6detail7textenc20convertCharToUnicode*; diff --git a/sd/source/ui/sidebar/MasterPageObserver.cxx b/sd/source/ui/sidebar/MasterPageObserver.cxx index 86a9c15e3f3d..57ea45fd6e23 100644 --- a/sd/source/ui/sidebar/MasterPageObserver.cxx +++ b/sd/source/ui/sidebar/MasterPageObserver.cxx @@ -162,9 +162,11 @@ void MasterPageObserver::Implementation::RegisterDocument ( aMasterPageSet.insert (pMasterPage->GetName()); } + bool bAlreadyExists = maUsedMasterPages.find(&rDocument) != maUsedMasterPages.end(); maUsedMasterPages[&rDocument] = aMasterPageSet; - StartListening (rDocument); + if (!bAlreadyExists) + StartListening (rDocument); } void MasterPageObserver::Implementation::UnregisterDocument ( diff --git a/svl/source/notify/lstner.cxx b/svl/source/notify/lstner.cxx index 4279e12f4a5c..0b3d2e9a3af5 100644 --- a/svl/source/notify/lstner.cxx +++ b/svl/source/notify/lstner.cxx @@ -21,17 +21,22 @@ #include <svl/hint.hxx> #include <svl/SfxBroadcaster.hxx> +#include <sal/backtrace.hxx> #include <algorithm> #include <cassert> #include <deque> - +#include <memory> +#include <map> typedef std::deque<SfxBroadcaster*> SfxBroadcasterArr_Impl; struct SfxListener::Impl { SfxBroadcasterArr_Impl maBCs; +#ifdef DBG_UTIL + std::map<SfxBroadcaster*, std::unique_ptr<BacktraceState>> maCallStacks; +#endif }; // simple ctor of class SfxListener @@ -68,27 +73,47 @@ void SfxListener::RemoveBroadcaster_Impl( SfxBroadcaster& rBroadcaster ) auto it = std::find( mpImpl->maBCs.begin(), mpImpl->maBCs.end(), &rBroadcaster ); if (it != mpImpl->maBCs.end()) { mpImpl->maBCs.erase( it ); +#ifdef DBG_UTIL + mpImpl->maCallStacks.erase( &rBroadcaster ); +#endif } } -// registers a specific SfxBroadcaster -void SfxListener::StartListening( SfxBroadcaster& rBroadcaster, bool bPreventDups ) +/** + Registers a specific SfxBroadcaster. + + Some code uses duplicates as a kind of ref-counting thing i.e. they add and remove listeners + on different code paths, and they only really stop listening when the last EndListening() is called. +*/ +void SfxListener::StartListening( SfxBroadcaster& rBroadcaster, bool bPreventDuplicates ) { - if ( !bPreventDups || !IsListening( rBroadcaster ) ) + bool bListeningAlready = IsListening( rBroadcaster ); + +#ifdef DBG_UTIL + if (bListeningAlready && !bPreventDuplicates) + { + auto f = mpImpl->maCallStacks.find( &rBroadcaster ); + SAL_INFO("svl", "previous StartListening call came from: " << sal_backtrace_to_string(f->second.get())); + } +#endif + assert(!(bListeningAlready && !bPreventDuplicates) && "duplicate listener, try building with DBG_UTIL to find the other insert site."); + + if ( !bListeningAlready || !bPreventDuplicates ) { rBroadcaster.AddListener(*this); mpImpl->maBCs.push_back( &rBroadcaster ); - +#ifdef DBG_UTIL + mpImpl->maCallStacks.emplace( &rBroadcaster, sal_backtrace_get(10) ); +#endif assert(IsListening(rBroadcaster) && "StartListening failed"); } } - // unregisters a specific SfxBroadcaster -void SfxListener::EndListening( SfxBroadcaster& rBroadcaster, bool bAllDups ) +void SfxListener::EndListening( SfxBroadcaster& rBroadcaster, bool bRemoveAllDuplicates ) { SfxBroadcasterArr_Impl::iterator beginIt = mpImpl->maBCs.begin(); do @@ -100,8 +125,11 @@ void SfxListener::EndListening( SfxBroadcaster& rBroadcaster, bool bAllDups ) } rBroadcaster.RemoveListener(*this); beginIt = mpImpl->maBCs.erase( it ); +#ifdef DBG_UTIL + mpImpl->maCallStacks.erase( &rBroadcaster ); +#endif } - while ( bAllDups ); + while ( bRemoveAllDuplicates ); } @@ -116,6 +144,9 @@ void SfxListener::EndListeningAll() pBC->RemoveListener(*this); mpImpl->maBCs.pop_front(); } +#ifdef DBG_UTIL + mpImpl->maCallStacks.clear(); +#endif } diff --git a/svx/source/unodraw/unoshape.cxx b/svx/source/unodraw/unoshape.cxx index 49dbba665cd4..d0e59bcbeb8b 100644 --- a/svx/source/unodraw/unoshape.cxx +++ b/svx/source/unodraw/unoshape.cxx @@ -353,15 +353,20 @@ void SvxShape::impl_initFromSdrObject() } osl_atomic_decrement( &m_refCount ); - mpModel = mpObj->GetModel(); + auto pNewModel = mpObj->GetModel(); + + if (pNewModel != mpModel) + { + if (mpModel) + EndListening( *mpModel ); + if (pNewModel) + StartListening( *pNewModel ); + mpModel = pNewModel; + } // #i40944# // Do not simply return when no model but do the type corrections // following below. - if(mpModel) - { - StartListening( *mpModel ); - } const SdrInventor nInventor = mpObj->GetObjInventor(); diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx index f058859f0401..5beb864aa1f6 100644 --- a/sw/source/core/layout/frmtool.cxx +++ b/sw/source/core/layout/frmtool.cxx @@ -3181,8 +3181,13 @@ public: void SwFrameHolder::SetFrame( SwFrame* pHold ) { bSet = true; - pFrame = pHold; - StartListening(*pHold); + if (pFrame != pHold) + { + if (pFrame) + EndListening(*pFrame); + StartListening(*pHold); + pFrame = pHold; + } } void SwFrameHolder::Reset() diff --git a/sw/source/uibase/utlui/navipi.cxx b/sw/source/uibase/utlui/navipi.cxx index e580cefb034f..9765031357ed 100644 --- a/sw/source/uibase/utlui/navipi.cxx +++ b/sw/source/uibase/utlui/navipi.cxx @@ -718,8 +718,6 @@ SwNavigationPI::SwNavigationPI(SfxBindings* _pBindings, m_aGlobalTree->SetFont(aFont); StartListening(*SfxGetpApp()); - if ( m_pCreateView ) - StartListening(*m_pCreateView); sal_uInt16 nNavId = m_aContentToolBox->GetItemId("navigation"); m_aContentToolBox->SetItemBits(nNavId, m_aContentToolBox->GetItemBits(nNavId) | ToolBoxItemBits::DROPDOWNONLY ); @@ -886,6 +884,7 @@ void SwNavigationPI::Notify( SfxBroadcaster& rBrdc, const SfxHint& rHint ) { if (rHint.GetId() == SfxHintId::Dying) { + EndListening(*m_pCreateView); m_pCreateView = nullptr; } } |