summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2021-07-16 12:45:21 +0100
committerAndras Timar <andras.timar@collabora.com>2022-02-20 09:40:46 +0100
commit152e5eeb613efe50190a1cdf18cb5bb06c46d9d7 (patch)
tree0232050338e8c0e6067faff13ac86e65ea043ba7
parentOnly change SwLayAction::m_bAgain via SetAgain (diff)
downloadcore-152e5eeb613efe50190a1cdf18cb5bb06c46d9d7.tar.gz
core-152e5eeb613efe50190a1cdf18cb5bb06c46d9d7.zip
crashtesting: UaF on layout of fdo53985-1.docx
Change-Id: Id8ca0d277f485347e21bd8d6d68de2a7de13de48 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119060 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r--sw/source/core/inc/layact.hxx8
-rw-r--r--sw/source/core/layout/layact.cxx51
2 files changed, 58 insertions, 1 deletions
diff --git a/sw/source/core/inc/layact.hxx b/sw/source/core/inc/layact.hxx
index fefe964eb97e..5445d26dfa76 100644
--- a/sw/source/core/inc/layact.hxx
+++ b/sw/source/core/inc/layact.hxx
@@ -66,6 +66,9 @@ class SwLayAction
std::unique_ptr<SwWait> m_pWait;
+ std::vector<SwFrame*> m_aFrameStack;
+ std::vector<std::unique_ptr<SwFrameDeleteGuard>> m_aFrameDeleteGuards;
+
// If a paragraph (or anything else) moved more than one page when
// formatting, it adds its new page number here.
// The InternalAction can then take the appropriate steps.
@@ -119,6 +122,9 @@ class SwLayAction
bool RemoveEmptyBrowserPages();
+ void PushFormatLayout(SwFrame* pLow);
+ void PopFormatLayout();
+
inline void CheckIdleEnd();
public:
@@ -150,7 +156,7 @@ public:
void SetReschedule ( bool bNew ) { m_bReschedule = bNew; }
void SetWaitAllowed ( bool bNew ) { m_bWaitAllowed = bNew; }
- void SetAgain(bool bAgain) { m_bAgain = bAgain; }
+ void SetAgain(bool bAgain);
void SetUpdateExpFields() {m_bUpdateExpFields = true; }
inline void SetCheckPageNum( sal_uInt16 nNew );
diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index 7acaf1495144..8d763fc22ce8 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -320,6 +320,53 @@ bool SwLayAction::RemoveEmptyBrowserPages()
return bRet;
}
+void SwLayAction::SetAgain(bool bAgain)
+{
+ if (bAgain == m_bAgain)
+ return;
+
+ m_bAgain = bAgain;
+
+ assert(m_aFrameStack.size() == m_aFrameDeleteGuards.size());
+ size_t nCount = m_aFrameStack.size();
+ if (m_bAgain)
+ {
+ // LayAction::FormatLayout is now flagged to exit early and will avoid
+ // dereferencing any SwFrames in the stack of FormatLayouts so allow
+ // their deletion
+ for (size_t i = 0; i < nCount; ++i)
+ m_aFrameDeleteGuards[i].reset();
+ }
+ else
+ {
+ // LayAction::FormatLayout is now continue normally and will
+ // dereference the top SwFrame in the stack of m_aFrameStack as each
+ // FormatLevel returns so disallow their deletion
+ for (size_t i = 0; i < nCount; ++i)
+ m_aFrameDeleteGuards[i] = std::make_unique<SwFrameDeleteGuard>(m_aFrameStack[i]);
+ }
+}
+
+void SwLayAction::PushFormatLayout(SwFrame* pLow)
+{
+ /* Workaround crash seen in crashtesting with fdo53985-1.docx
+
+ Lock pLow against getting deleted when it will be dereferenced
+ after FormatLayout
+
+ If SetAgain is called to make SwLayAction exit early to avoid that
+ dereference, then it clears these guards
+ */
+ m_aFrameStack.push_back(pLow);
+ m_aFrameDeleteGuards.push_back(std::make_unique<SwFrameDeleteGuard>(pLow));
+}
+
+void SwLayAction::PopFormatLayout()
+{
+ m_aFrameDeleteGuards.pop_back();
+ m_aFrameStack.pop_back();
+}
+
void SwLayAction::Action(OutputDevice* pRenderContext)
{
m_bActionInProgress = true;
@@ -1384,7 +1431,11 @@ bool SwLayAction::FormatLayout( OutputDevice *pRenderContext, SwLayoutFrame *pLa
}
// Skip the ones already registered for deletion
else if( !pLow->IsSctFrame() || static_cast<SwSectionFrame*>(pLow)->GetSection() )
+ {
+ PushFormatLayout(pLow);
bChanged |= FormatLayout( pRenderContext, static_cast<SwLayoutFrame*>(pLow), bAddRect );
+ PopFormatLayout();
+ }
}
else if ( m_pImp->GetShell()->IsPaintLocked() )
// Shortcut to minimize the cycles. With Lock, the