summaryrefslogtreecommitdiff
path: root/sw/source/core/bastyp
diff options
context:
space:
mode:
authorMichael Stahl <Michael.Stahl@cib.de>2019-05-27 18:55:31 +0200
committerMichael Stahl <Michael.Stahl@cib.de>2019-05-28 14:12:15 +0200
commit1424d51a44ed2fa8b37b2d132af8a608a170ec8e (patch)
tree597483b5df82cd16d23ec060cfc79c66a7fbca74 /sw/source/core/bastyp
parent14c4e6155271d04f0a86029635d0a4c0b460146a (diff)
tdf#125475 sw: update SwTextFrames when SwTextLine cache shrinks
SwCache::DeleteObj() may decide to shrink the cache, and then the SwTextFrame::mnCacheIndex goes stale, because only SwCacheObj::m_nCachePos is updated. In this bugdoc, this can happen *inside* SwTextFrame::Format(), where first it succeeds to find an existing SwTextLine, then some footnotes anchored in this paragraph are moved around and formatted, creating new SwTextLines, and SwCache::DeleteObj is called. Later, any access of the original frame's SwTextLine fails to find it and eventually some null pointer crash happens. Newly added SwTextLine::UpdateCachePos() requires that SwTextFrame lives longer than its SwTextLine; there was another problem with that, because SwTextFrame::FormatEmpty() was throwing away the mnCacheIndex, which could then cause a second SwTextLine to be created for the same SwTextFrame, and the first one is not deleted until it falls to the bottom of the LRU list. Apprently for this particular document the problem didn't happen before commit 3d37463eec0c891243a8971a34903b2da01c9e24 and/or commit 31ae7509003b1e650463ee1468c0b315ba13efe6 but that is mostly luck. Change-Id: I7bef1b340a453d6dd44d51a1dc69ee5fd0b697db Reviewed-on: https://gerrit.libreoffice.org/73047 Tested-by: Jenkins Reviewed-by: Michael Stahl <Michael.Stahl@cib.de>
Diffstat (limited to 'sw/source/core/bastyp')
-rw-r--r--sw/source/core/bastyp/swcache.cxx17
1 files changed, 13 insertions, 4 deletions
diff --git a/sw/source/core/bastyp/swcache.cxx b/sw/source/core/bastyp/swcache.cxx
index 64eb233b6bf7..443e267b9006 100644
--- a/sw/source/core/bastyp/swcache.cxx
+++ b/sw/source/core/bastyp/swcache.cxx
@@ -296,6 +296,7 @@ void SwCache::DeleteObj( SwCacheObj *pObj )
pObj->GetNext()->SetPrev( pObj->GetPrev() );
m_aFreePositions.push_back( pObj->GetCachePos() );
+ assert(m_aCacheObjects[pObj->GetCachePos()].get() == pObj);
m_aCacheObjects[pObj->GetCachePos()] = nullptr; // deletes pObj
CHECK;
@@ -340,10 +341,18 @@ void SwCache::Delete( const void *pOwner )
DeleteObj( pObj );
}
-bool SwCache::Insert( SwCacheObj *pNew )
+bool SwCache::Insert(SwCacheObj *const pNew, bool const isDuplicateOwnerAllowed)
{
CHECK;
OSL_ENSURE( !pNew->GetPrev() && !pNew->GetNext(), "New but not new." );
+ if (!isDuplicateOwnerAllowed)
+ {
+ for (auto const & rpObj : m_aCacheObjects)
+ { // check owner doesn't have a cache object yet; required for SwTextLine
+ assert(!rpObj || rpObj->GetOwner() != pNew->GetOwner());
+ (void) rpObj;
+ }
+ }
sal_uInt16 nPos;
if ( m_aCacheObjects.size() < m_nCurMax )
@@ -374,7 +383,7 @@ bool SwCache::Insert( SwCacheObj *pNew )
{
SAL_WARN("sw.core", "SwCache overflow.");
IncreaseMax(100); // embiggen & try again
- return Insert(pNew);
+ return Insert(pNew, isDuplicateOwnerAllowed);
}
nPos = pObj->GetCachePos();
@@ -485,12 +494,12 @@ SwCacheAccess::~SwCacheAccess()
m_pObj->Unlock();
}
-void SwCacheAccess::Get_()
+void SwCacheAccess::Get_(bool const isDuplicateOwnerAllowed)
{
OSL_ENSURE( !m_pObj, "SwCacheAcces Obj already available." );
m_pObj = NewObj();
- if ( !m_rCache.Insert( m_pObj ) )
+ if (!m_rCache.Insert(m_pObj, isDuplicateOwnerAllowed))
{
delete m_pObj;
m_pObj = nullptr;