sw/qa/core/doc/data/header-footer-delete.docx |binary
 sw/qa/core/doc/doc.cxx                        |   10 ++++++++
 sw/source/core/doc/docbm.cxx                  |   31 +++++++++++++-------------
 3 files changed, 26 insertions(+), 15 deletions(-)

New commits:
commit bd892f3ba96fae1f0a151734053da0b39ca69c86
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu Oct 27 15:38:28 2022 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Oct 27 16:31:35 2022 +0200

    crashtesting: fix PDF export of tdf98567-1.docx
    
    Importing tdf98567-1.docx crashed with debug STL since commit
    47bc36c0f87ec2d0329260bcb98d62c7667a5dd1 (sw: make sure mark container
    is sorted before calling equal_range(), 2022-10-24).
    
    The problem is that sw::mark::MarkManager::deleteMark() calls
    DeregisterFromDoc(), which can call selection change listeners, which
    may mutate the container.
    
    Fix the problem by delaying the DeregisterFromDoc call using
    an ILazyDeleter for DDE bookmarks.
    
    Change-Id: Ia4e8ec379dc0c597db8fe5d91d55af09363350c4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141907
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/qa/core/doc/data/header-footer-delete.docx 
b/sw/qa/core/doc/data/header-footer-delete.docx
new file mode 100644
index 000000000000..e6cc4273151d
Binary files /dev/null and b/sw/qa/core/doc/data/header-footer-delete.docx 
differ
diff --git a/sw/qa/core/doc/doc.cxx b/sw/qa/core/doc/doc.cxx
index 53ac1a9e2b45..4a7324e7905f 100644
--- a/sw/qa/core/doc/doc.cxx
+++ b/sw/qa/core/doc/doc.cxx
@@ -425,6 +425,16 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, 
testBookmarkDeleteRedline)
     
pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::ShowInsert);
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testHeaderFooterDelete)
+{
+    // Given a document with bookmarks in header/footers:
+    // When importing that document:
+    // Then make sure that we don't crash:
+    // Without the accompanying fix in place, this test would have crashed, an 
invalidated iterator
+    // was used in sw::mark::MarkManager::deleteMarks().
+    createSwDoc(DATA_DIRECTORY, "header-footer-delete.docx");
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx
index 6db0b5b51862..3243a79c55ff 100644
--- a/sw/source/core/doc/docbm.cxx
+++ b/sw/source/core/doc/docbm.cxx
@@ -1219,6 +1219,21 @@ namespace sw::mark
         }
     };
 
+    struct LazyDdeBookmarkDeleter : public IDocumentMarkAccess::ILazyDeleter
+    {
+        std::unique_ptr<DdeBookmark> m_pDdeBookmark;
+        SwDoc& m_rDoc;
+        LazyDdeBookmarkDeleter(DdeBookmark *const pDdeBookmark, SwDoc& rDoc)
+            : m_pDdeBookmark(pDdeBookmark), m_rDoc(rDoc)
+        {
+            assert(pDdeBookmark);
+        }
+        virtual ~LazyDdeBookmarkDeleter() override
+        {
+            m_pDdeBookmark->DeregisterFromDoc(m_rDoc);
+        }
+    };
+
     }
 
     std::unique_ptr<IDocumentMarkAccess::ILazyDeleter>
@@ -1292,21 +1307,7 @@ namespace sw::mark
         DdeBookmark* const pDdeBookmark = dynamic_cast<DdeBookmark*>(pMark);
         if (pDdeBookmark)
         {
-            pDdeBookmark->DeregisterFromDoc(m_rDoc);
-
-            // Update aI, possibly a selection listener invalidated the 
iterators of m_vAllMarks.
-            assureSortedMarkContainers();
-            auto [it, endIt] = equal_range(m_vAllMarks.begin(), 
m_vAllMarks.end(),
-                                           pMark->GetMarkStart(), 
CompareIMarkStartsBefore());
-            for (; it != endIt; ++it)
-            {
-                if (*it == pMark)
-                {
-                    aI = m_vAllMarks.begin();
-                    std::advance(aI, 
std::distance<container_t::const_iterator>(aI, it));
-                    break;
-                }
-            }
+            ret.reset(new 
LazyDdeBookmarkDeleter(dynamic_cast<DdeBookmark*>(pMark), m_rDoc));
         }
 
         m_vAllMarks.erase(aI);

Reply via email to