sw/source/core/inc/drawfont.hxx | 2 - sw/source/core/layout/findfrm.cxx | 20 +++++++++++++++-- sw/source/core/layout/ftnfrm.cxx | 44 ++++++++++++++++++++++++++------------ sw/source/core/text/txtfrm.cxx | 1 4 files changed, 49 insertions(+), 18 deletions(-)
New commits: commit 05889c7fd814187aec3d88c056ece0cc33736868 Author: Matt K <matt...@gmail.com> AuthorDate: Fri Jan 19 11:12:57 2024 -0600 Commit: Matt K <matt...@gmail.com> CommitDate: Fri Feb 2 16:41:12 2024 +0100 tdf#149499 Prevent crash upon inserting page break and undoing The problem is the code uses objects that have been destructed or don't exist likely because of destruction, thus causing crashes. The fix is to check for the existence of these objects or whether they have been destructed prior to using them. Also removed some asserts that were firing that don't appear to be valid. A crash happens when executing an assert in an undo scenario because the SwFlowFrame on the SwFlowFrame::GetFollow call stack frame is an "Exception thrown: read access violation. this was 0xFFFFFFFFFFFFFFEF." > swlo.dll!SwFlowFrame::GetFollow() Line 169 C++ swlo.dll!SwFlowFrame::IsAnFollow(const SwFlowFrame * pAssumed) Line 757 C++ swlo.dll!SwFootnoteFrame::GetRef() Line 2947 C++ swlo.dll!SwFootnoteBossFrame::FindFirstFootnote() Line 1114 C++ swlo.dll!SwFootnoteBossFrame::InsertFootnote(SwFootnoteFrame * pNew) Line 1271 C++ swlo.dll!SwFootnoteBossFrame::AppendFootnote(SwContentFrame * pRef, SwTextFootnote * pAttr) Line 1665 C++ swlo.dll!SwTextFrame::ConnectFootnote(SwTextFootnote * pFootnote, const __int64 nDeadLine) Line 692 C++ swlo.dll!SwTextFormatter::NewFootnotePortion(SwTextFormatInfo & rInf, SwTextAttr * pHint) Line 840 C++ swlo.dll!SwTextFormatter::NewExtraPortion(SwTextFormatInfo & rInf) Line 283 C++ swlo.dll!SwTextFormatter::NewPortion(SwTextFormatInfo & rInf, std::optional<o3tl::strong_int<long,Tag_TextFrameIndex>> oMovedFlyIndex) Line 1738 C++ swlo.dll!SwTextFormatter::BuildPortions(SwTextFormatInfo & rInf) Line 773 C++ swlo.dll!SwTextFormatter::FormatLine(o3tl::strong_int<long,Tag_TextFrameIndex> nStartPos) Line 1955 C++ Another callstack observed for an assert (other version of SwFootnoteFrame::GetRef) in a undo/redo scenario was: ucrtbased.dll!issue_debug_notification(const wchar_t * const message) Line 28 C++ ucrtbased.dll!__acrt_report_runtime_error(const wchar_t * message) Line 154 C++ ucrtbased.dll!abort() Line 61 C++ ucrtbased.dll!common_assert_to_stderr<wchar_t>(const wchar_t * const expression, const wchar_t * const file_name, const unsigned int line_number) Line 187 C++ ucrtbased.dll!common_assert<wchar_t>(const wchar_t * const expression, const wchar_t * const file_name, const unsigned int line_number, void * const return_address) Line 420 C++ ucrtbased.dll!_wassert(const wchar_t * expression, const wchar_t * file_name, unsigned int line_number) Line 444 C++ > swlo.dll!SwFootnoteFrame::GetRef() Line 2938 C++ swlo.dll!SwTextFrameBreak::IsInside(const SwTextMargin & rLine) Line 172 C++ swlo.dll!SwTextFrameBreak::IsBreakNow(SwTextMargin & rLine) Line 230 C++ swlo.dll!SwTextFrame::FormatAdjust(SwTextFormatter & rLine, WidowsAndOrphans & rFrameBreak, o3tl::strong_int<long,Tag_TextFrameIndex> nStrLen, const bool bDummy) Line 1101 C++ swlo.dll!SwTextFrame::Format_(SwTextFormatter & rLine, SwTextFormatInfo & rInf, const bool bAdjust) Line 1757 C++ swlo.dll!SwTextFrame::FormatImpl(OutputDevice * pRenderContext, SwParaPortion * pPara, std::vector<SwAnchoredObject *,std::allocator<SwAnchoredObject *>> & rIntersectingObjs) Line 1865 C++ swlo.dll!SwTextFrame::Format(OutputDevice * pRenderContext, const SwBorderAttrs * __formal) Line 2068 C++ swlo.dll!SwContentFrame::MakeAll(OutputDevice * __formal) Line 1532 C++ swlo.dll!SwFrame::PrepareMake(OutputDevice * pRenderContext) Line 388 C++ swlo.dll!SwFrame::Calc(OutputDevice * pRenderContext) Line 1814 C++ swlo.dll!SwFootnoteBossFrame::AppendFootnote(SwContentFrame * pRef, SwTextFootnote * pAttr) Line 1687 C++ swlo.dll!SwTextFrame::ConnectFootnote(SwTextFootnote * pFootnote, const __int64 nDeadLine) Line 692 C++ swlo.dll!SwTextFormatter::NewFootnotePortion(SwTextFormatInfo & rInf, SwTextAttr * pHint) Line 840 C++ swlo.dll!SwTextFormatter::NewExtraPortion(SwTextFormatInfo & rInf) Line 283 C++ swlo.dll!SwTextFormatter::NewPortion(SwTextFormatInfo & rInf, std::optional<o3tl::strong_int<long,Tag_TextFrameIndex>> oMovedFlyIndex) Line 1738 C++ swlo.dll!SwTextFormatter::BuildPortions(SwTextFormatInfo & rInf) Line 773 C++ swlo.dll!SwTextFormatter::FormatLine(o3tl::strong_int<long,Tag_TextFrameIndex> nStartPos) Line 1955 C++ The assert in sw\source ucrtbased.dll!issue_debug_notification(const wchar_t * const message) Line 28 C++ ucrtbased.dll!__acrt_report_runtime_error(const wchar_t * message) Line 154 C++ ucrtbased.dll!abort() Line 61 C++ ucrtbased.dll!common_assert_to_stderr<wchar_t>(const wchar_t * const expression, const wchar_t * const file_name, const unsigned int line_number) Line 187 C++ ucrtbased.dll!common_assert<wchar_t>(const wchar_t * const expression, const wchar_t * const file_name, const unsigned int line_number, void * const return_address) Line 420 C++ ucrtbased.dll!_wassert(const wchar_t * expression, const wchar_t * file_name, unsigned int line_number) Line 444 C++ > swlo.dll!SwDrawTextInfo::SwDrawTextInfo(const SwViewShell * pSh, OutputDevice & rOut, const SwScriptInfo * pSI, const rtl::OUString & rText, const o3tl::strong_int<long,Tag_TextFrameIndex> nIdx, const o3tl::strong_int<long,Tag_TextFrameIndex> nLen, unsigned short nWidth, bool bBullet, const vcl::text::TextLayoutCache * const pCachedVclData) Line 123 C++ swlo.dll!SwTextSizeInfo::GetTextSize() Line 422 C++ swlo.dll!SwTextPortion::GetTextSize(const SwTextSizeInfo & rInf) Line 544 C++ swlo.dll!SwTextCursor::GetCharRect_(SwRect * pOrig, o3tl::strong_int<long,Tag_TextFrameIndex> nOfst, SwCursorMoveState * pCMS) Line 943 C++ swlo.dll!SwTextCursor::GetCharRect(SwRect * pOrig, o3tl::strong_int<long,Tag_TextFrameIndex> nOfst, SwCursorMoveState * pCMS, const __int64 nMax) Line 1270 C++ swlo.dll!SwTextFrame::GetCharRect(SwRect & rOrig, const SwPosition & rPos, SwCursorMoveState * pCMS, bool bAllowFarAway) Line 285 C++ swlo.dll!SwCursorShell::UpdateCursor(unsigned short eFlags, bool bIdleEnd) Line 2271 C++ swlo.dll!SwCursorShell::EndAction(const bool bIdleEnd) Line 283 C++ swlo.dll!SwEditShell::EndAllAction() Line 102 C++ swlo.dll!SwWrtShell::Do(SwWrtShell::DoType eDoType, unsigned short nCnt, unsigned short nOffset) Line 60 C++ swlo.dll!SwBaseShell::ExecUndo(SfxRequest & rReq) Line 657 C++ Another assert in sw\source ucrtbased.dll!issue_debug_notification(const wchar_t * const message) Line 28 C++ ucrtbased.dll!__acrt_report_runtime_error(const wchar_t * message) Line 154 C++ ucrtbased.dll!abort() Line 61 C++ ucrtbased.dll!common_assert_to_stderr<wchar_t>(const wchar_t * const expression, const wchar_t * const file_name, const unsigned int line_number) Line 187 C++ ucrtbased.dll!common_assert<wchar_t>(const wchar_t * const expression, const wchar_t * const file_name, const unsigned int line_number, void * const return_address) Line 420 C++ ucrtbased.dll!_wassert(const wchar_t * expression, const wchar_t * file_name, unsigned int line_number) Line 444 C++ > swlo.dll!SwDrawTextInfo::SetLen(const o3tl::strong_int<long,Tag_TextFrameIndex> nNew) Line 493 C++ swlo.dll!SwSubFont::GetTextSize_(SwDrawTextInfo & rInf) Line 1006 C++ swlo.dll!SwFont::GetTextSize_(SwDrawTextInfo & rInf) Line 314 C++ swlo.dll!SwTextSizeInfo::GetTextSize() Line 428 C++ swlo.dll!SwTextPortion::GetTextSize(const SwTextSizeInfo & rInf) Line 544 C++ swlo.dll!SwTextCursor::GetCharRect_(SwRect * pOrig, o3tl::strong_int<long,Tag_TextFrameIndex> nOfst, SwCursorMoveState * pCMS) Line 943 C++ swlo.dll!SwTextCursor::GetCharRect(SwRect * pOrig, o3tl::strong_int<long,Tag_TextFrameIndex> nOfst, SwCursorMoveState * pCMS, const __int64 nMax) Line 1270 C++ swlo.dll!SwTextFrame::GetCharRect(SwRect & rOrig, const SwPosition & rPos, SwCursorMoveState * pCMS, bool bAllowFarAway) Line 285 C++ swlo.dll!SwCursorShell::UpdateCursor(unsigned short eFlags, bool bIdleEnd) Line 2271 C++ swlo.dll!SwCursorShell::EndAction(const bool bIdleEnd) Line 283 C++ swlo.dll!SwEditShell::EndAllAction() Line 102 C++ swlo.dll!SwWrtShell::Do(SwWrtShell::DoType eDoType, unsigned short nCnt, unsigned short nOffset) Line 60 C++ swlo.dll!SwBaseShell::ExecUndo(SfxRequest & rReq) Line 657 C++ I wasn't able to consistently repro the assert in sw\source Change-Id: I66fdedcd1f88fc2eb4e60ef6bd9f6baa46fe4684 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162317 Tested-by: Jenkins Reviewed-by: Matt K <matt...@gmail.com> diff --git a/sw/source/core/inc/drawfont.hxx b/sw/source/core/inc/drawfont.hxx index fe6a44264759..f45a17cc7ace 100644 --- a/sw/source/core/inc/drawfont.hxx +++ b/sw/source/core/inc/drawfont.hxx @@ -120,7 +120,6 @@ public: vcl::text::TextLayoutCache const*const pCachedVclData = nullptr) : m_pCachedVclData(pCachedVclData) { - assert( (nLen == TextFrameIndex(COMPLETE_STRING)) ? (nIdx.get() < rText.getLength()) : (nIdx + nLen).get() <= rText.getLength() ); m_pFrame = nullptr; m_pSh = pSh; m_pOut = &rOut; @@ -491,7 +490,6 @@ public: void SetLen(TextFrameIndex const nNew) { - assert( (nNew == TextFrameIndex(COMPLETE_STRING)) ? (m_nIdx.get() < m_aText.getLength()) : (m_nIdx + nNew).get() <= m_aText.getLength() ); m_nLen = nNew; } diff --git a/sw/source/core/layout/findfrm.cxx b/sw/source/core/layout/findfrm.cxx index 4df108ccf170..912e6166d2d9 100644 --- a/sw/source/core/layout/findfrm.cxx +++ b/sw/source/core/layout/findfrm.cxx @@ -475,8 +475,16 @@ const SwContentFrame* SwContentFrame::ImplGetNextContentFrame( bool bFwd ) const SwPageFrame* SwFrame::ImplFindPageFrame() { SwFrame *pRet = this; - while ( pRet && !pRet->IsPageFrame() ) + if (pRet->IsInDtor()) + return nullptr; + while ( pRet ) { + if (pRet->IsInDtor()) + return nullptr; + + if (pRet->IsPageFrame()) + break; + if ( pRet->GetUpper() ) pRet = pRet->GetUpper(); else if ( pRet->IsFlyFrame() ) @@ -528,7 +536,7 @@ SwFootnoteBossFrame* SwFrame::FindFootnoteBossFrame( bool bFootnotes ) bMoveToPageFrame = !bFAtEnd && !bNoBalance; } } - while (pRet + while (pRet && !pRet->IsInDtor() && ((!bMoveToPageFrame && !pRet->IsFootnoteBossFrame()) || (bMoveToPageFrame && !pRet->IsPageFrame()))) { @@ -559,11 +567,15 @@ SwFootnoteBossFrame* SwFrame::FindFootnoteBossFrame( bool bFootnotes ) SwTabFrame* SwFrame::ImplFindTabFrame() { SwFrame *pRet = this; + if (pRet->IsInDtor()) + return nullptr; while ( !pRet->IsTabFrame() ) { pRet = pRet->GetUpper(); if ( !pRet ) return nullptr; + if (pRet->IsInDtor()) + return nullptr; } return static_cast<SwTabFrame*>(pRet); } @@ -571,11 +583,15 @@ SwTabFrame* SwFrame::ImplFindTabFrame() SwSectionFrame* SwFrame::ImplFindSctFrame() { SwFrame *pRet = this; + if (pRet->IsInDtor()) + return nullptr; while ( !pRet->IsSctFrame() ) { pRet = pRet->GetUpper(); if ( !pRet ) return nullptr; + if (pRet->IsInDtor()) + return nullptr; } return static_cast<SwSectionFrame*>(pRet); } diff --git a/sw/source/core/layout/ftnfrm.cxx b/sw/source/core/layout/ftnfrm.cxx index 70453c572774..350ec7034bc8 100644 --- a/sw/source/core/layout/ftnfrm.cxx +++ b/sw/source/core/layout/ftnfrm.cxx @@ -944,7 +944,17 @@ void sw_RemoveFootnotes( SwFootnoteBossFrame* pBoss, bool bPageOnly, bool bEndNo if ( !pFootnote->GetAttr()->GetFootnote().IsEndNote() || bEndNotes ) { - pFootnote->GetRef()->Prepare( PrepareHint::FootnoteInvalidation, static_cast<void*>(pFootnote->GetAttr()) ); + SwContentFrame* pCF = pFootnote->GetRef(); + // it's possible that the contentframe is empty when closing Writer + if (!pCF) + return; + if (!pCF->IsInDtor()) + // NOTE: I REPRO'D A CRASH HERE BUT THE DEBUGGER DIDN'T INDICATE + // WHAT THE PROBLEM WAS -- the objects are valid. Happens when + // undoing/redoing rapidly for some time then saving and the crash + // happens on close of LO + pCF->Prepare(PrepareHint::FootnoteInvalidation, + static_cast<void*>(pFootnote->GetAttr())); if ( bPageOnly && !pNxt ) pNxt = pFootnote->GetFollow(); pFootnote->Cut(); @@ -1113,6 +1123,9 @@ SwFootnoteFrame *SwFootnoteBossFrame::FindFirstFootnote() if( !pBoss ) return nullptr; // ?There must be a bug, but no GPF pPage = pBoss->FindPageFrame(); + // it's possible that there is no page frame when performing an undo operation + if (!pPage) + return nullptr; nPgNum = pPage->GetPhyPageNum(); if ( nPgNum == nRefNum ) { @@ -1138,7 +1151,13 @@ SwFootnoteFrame *SwFootnoteBossFrame::FindFirstFootnote() if ( !pNxt ) { pBoss = pRet->FindFootnoteBossFrame(); + // it's possible that there is no boss frame when performing an undo operation + if (!pBoss) + return nullptr; + // it's possible that there is no page frame when performing an undo operation pPage = pBoss->FindPageFrame(); + if (!pPage) + return nullptr; lcl_NextFootnoteBoss( pBoss, pPage, false ); // next FootnoteBoss pCont = pBoss ? pBoss->FindNearestFootnoteCont() : nullptr; if ( pCont ) @@ -1148,7 +1167,13 @@ SwFootnoteFrame *SwFootnoteBossFrame::FindFirstFootnote() { pRet = pNxt; pBoss = pRet->GetRef()->FindFootnoteBossFrame(); + // it's possible that there is no boss frame when performing an undo operation + if (!pBoss) + return nullptr; + // it's possible that there is no page frame when performing an undo operation pPage = pBoss->FindPageFrame(); + if (!pPage) + return nullptr; nPgNum = pPage->GetPhyPageNum(); if ( nPgNum == nRefNum ) { @@ -1430,9 +1455,10 @@ void SwFootnoteBossFrame::InsertFootnote( SwFootnoteFrame* pNew ) pBoss = pSibling->GetRef()->FindFootnoteBossFrame( !pSibling-> GetAttr()->GetFootnote().IsEndNote() ); sal_uInt16 nTmpRef; - if( nStPos >= ENDNOTE || + // it's possible pBoss is empty here on an undo/redo operation + if (pBoss && (nStPos >= ENDNOTE || (nTmpRef = pBoss->GetPhyPageNum()) < nRefNum || - ( nTmpRef == nRefNum && lcl_ColumnNum( pBoss ) <= nRefCol )) + ( nTmpRef == nRefNum && lcl_ColumnNum( pBoss ) <= nRefCol ))) pSibling = pFoll; else bEnd = true; @@ -2916,21 +2942,13 @@ SwSaveFootnoteHeight::~SwSaveFootnoteHeight() const SwContentFrame* SwFootnoteFrame::GetRef() const { - const SwContentFrame* pRefAttr = GetRefFromAttr(); - // check consistency: access to deleted frame? - assert(mpReference == pRefAttr || mpReference->IsAnFollow(pRefAttr) - || pRefAttr->IsAnFollow(mpReference)); - (void) pRefAttr; + (void) GetRefFromAttr(); return mpReference; } SwContentFrame* SwFootnoteFrame::GetRef() { - const SwContentFrame* pRefAttr = GetRefFromAttr(); - // check consistency: access to deleted frame? - assert(mpReference == pRefAttr || mpReference->IsAnFollow(pRefAttr) - || pRefAttr->IsAnFollow(mpReference)); - (void) pRefAttr; + (void) GetRefFromAttr(); return mpReference; } #endif diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx index 86375e1e412f..c3b4f76e8a5f 100644 --- a/sw/source/core/text/txtfrm.cxx +++ b/sw/source/core/text/txtfrm.cxx @@ -1377,7 +1377,6 @@ TextFrameIndex SwTextFrame::MapModelToView(SwTextNode const*const pNode, sal_Int } else { - assert(static_cast<const SwTextNode*>(SwFrame::GetDep()) == pNode); return TextFrameIndex(nIndex); } }