summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editeng/source/editeng/impedit5.cxx2
-rw-r--r--include/sal/backtrace.hxx44
-rw-r--r--include/svl/lstner.hxx4
-rw-r--r--sal/osl/unx/backtraceapi.cxx30
-rw-r--r--sal/osl/w32/backtrace.cxx51
-rw-r--r--sal/util/sal.map6
-rw-r--r--sd/source/ui/sidebar/MasterPageObserver.cxx4
-rw-r--r--svl/source/notify/lstner.cxx47
-rw-r--r--svx/source/unodraw/unoshape.cxx15
-rw-r--r--sw/source/core/layout/frmtool.cxx9
-rw-r--r--sw/source/uibase/utlui/navipi.cxx3
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;
}
}