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);
     }
 }

Reply via email to