sw/source/core/doc/DocumentContentOperationsManager.cxx |   12 +++++++++++-
 sw/source/core/doc/doccorr.cxx                          |    5 ++++-
 2 files changed, 15 insertions(+), 2 deletions(-)

New commits:
commit e8d36908ca57af37dfea747d32356d3175e2a9b0
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Thu Jan 5 12:32:09 2023 +0100
Commit:     Caolán McNamara <caol...@redhat.com>
CommitDate: Fri Jan 6 20:45:25 2023 +0000

    tdf#152710 sw: invalidate SwUnoCursors properly in DeleteRangeImpl()
    
    This crashes with:
    
     list.cxx:44: corrupt document structure, bailing out of infinite loop
     ndtxt.cxx:5437: void SwTextNode::TriggerNodeUpdate(const 
sw::LegacyModifyHint&): Assertion `dynamic_cast<SwTextFormatColl 
const*>(static_cast<const SwFormatChg*>(pOldValue)->pChangedFormat)' failed.
    
    Because the redline from 7 to 9 is deleted, but then some cursor ends up
    on node 10 which is invalid as it is an end node.
    
    [   6] 0x60666a0            StartNode ,
    [   7]  0x61195e0           StartNode ,
    [   8]   0x61197a8           TextNode "tainment",
    [   9]  0x6119670             EndNode ,
    [  10] 0x6066730              EndNode ,
    
    The first problem is that DeleteRangeImpl() uses the point node as the
    target position for PaMCorrAbs(), but in this case the point node will
    be deleted.
    
    PaMCorrAbs() has a check to invalidate SwUnoCursors that would be moved
    out of their parent sections, but due to the first problem it can't
    check it, and the second problem is that lcl_FindUnoCursorSection()
    doesn't work on redline sections, as those have node type
    SwNormalStartNode.
    
    After fixing the invalidation, subsequent access to the SwXTextCursor
    throws exceptions and importing the file fails.
    
    (regression from commit 477e489e71b4a96ff10d9f2d2b802d91dec3e319)
    
    Thanks to Dave Gilbert for identifying the problematic DeleteRange()
    call.
    
    Change-Id: I48a373cc122073b82bc47513fdae684f45b0efb8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145077
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 8e05bdd26f21fc304978ff3b454cf355841ec75f)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145010
    Reviewed-by: Caolán McNamara <caol...@redhat.com>

diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 94f3baf31907..f50308cd03af 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -4242,7 +4242,17 @@ bool 
DocumentContentOperationsManager::DeleteRangeImpl(SwPaM & rPam, SwDeleteFla
     // Move all cursors out of the deleted range, but first copy the
     // passed PaM, because it could be a cursor that would be moved!
     SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
-    ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
+    {
+        // tdf#152710 target position must be on node that survives deletion
+        // so that PaMCorrAbs can invalidate SwUnoCursors properly
+        SwPosition const pos(aDelPam.GetPoint()->GetNode().IsContentNode()
+                ? *aDelPam.GetPoint()
+                : aDelPam.GetMark()->GetNode().IsContentNode()
+                    ? *aDelPam.GetMark()
+                    // this would be the result in SwNodes::RemoveNode()
+                    : SwPosition(aDelPam.End()->GetNode(), SwNodeOffset(+1)));
+        ::PaMCorrAbs(aDelPam, pos);
+    }
 
     bool const bSuccess( DeleteRangeImplImpl(aDelPam, flags) );
     if (bSuccess)
diff --git a/sw/source/core/doc/doccorr.cxx b/sw/source/core/doc/doccorr.cxx
index 8cf23cc43ab5..c26bced7ac00 100644
--- a/sw/source/core/doc/doccorr.cxx
+++ b/sw/source/core/doc/doccorr.cxx
@@ -37,8 +37,11 @@ namespace
         const SwStartNode* pStartNode = rNode.StartOfSectionNode();
         while( ( pStartNode != nullptr ) &&
                ( pStartNode->StartOfSectionNode() != pStartNode ) &&
-               ( pStartNode->GetStartNodeType() == SwNormalStartNode ) )
+               // section node is only start node allowing overlapped delete
+               pStartNode->IsSectionNode() )
+        {
             pStartNode = pStartNode->StartOfSectionNode();
+        }
 
         return pStartNode;
     }

Reply via email to