sw/inc/charfmt.hxx                |    3 ++-
 sw/inc/fmtcol.hxx                 |    2 +-
 sw/qa/core/doc/doc.cxx            |   30 ++++++++++++++++++++++++++++++
 sw/source/core/doc/fmtcol.cxx     |   15 ++++++++++++++-
 sw/source/core/txtnode/chrfmt.cxx |   19 ++++++++++++++++++-
 sw/source/uibase/app/docstyle.cxx |    4 ++--
 6 files changed, 67 insertions(+), 6 deletions(-)

New commits:
commit 3aff88ae021c571b6e218f6e2a0f62728bb86394
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Oct 3 23:04:41 2022 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue Oct 4 08:21:57 2022 +0200

    tdf#151094 ODT export: fix crash when linked paragraph style is deleted
    
    If a document contains a linked paragraph-character style pair and the
    paragraph style gets deleted, we crash on save.
    
    Commit 3227975c0f42ff23d528f5ab94b4538c8af764c (sw: paragraph styles:
    add doc model & UNO API for a linked character style, 2021-09-24) added
    support for linked para/char styles, but it failed to get the lifecycle
    correctly when it comes to deleting these styles.
    
    Fix the dangling para/char style references by explicitly looking what
    styles may refer to us and clear their references.
    
    An alternative would be to clear the "link" pointer of our own "link"
    pointer only, but broken documents may e.g. link multiple paragraph
    styles to a single character style, so this is probably not enough.
    
    Change-Id: I9465d43e90cf54c3c02bffda3e7c75b52c543a65
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140930
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/inc/charfmt.hxx b/sw/inc/charfmt.hxx
index e08d2f5f3a3f..84571d26263a 100644
--- a/sw/inc/charfmt.hxx
+++ b/sw/inc/charfmt.hxx
@@ -36,10 +36,11 @@ class SW_DLLPUBLIC SwCharFormat final : public SwFormat
     {}
 
 public:
+    ~SwCharFormat();
 
     void dumpAsXml(xmlTextWriterPtr pWriter) const;
 
-    void SetLinkedParaFormat(SwTextFormatColl& rLink);
+    void SetLinkedParaFormat(SwTextFormatColl* pLink);
 
     const SwTextFormatColl* GetLinkedParaFormat() const;
 };
diff --git a/sw/inc/fmtcol.hxx b/sw/inc/fmtcol.hxx
index b5706dc0761b..00e5208b73f4 100644
--- a/sw/inc/fmtcol.hxx
+++ b/sw/inc/fmtcol.hxx
@@ -103,7 +103,7 @@ public:
     inline void SetNextTextFormatColl(SwTextFormatColl& rNext);
     SwTextFormatColl& GetNextTextFormatColl() const { return 
*mpNextTextFormatColl; }
 
-    void SetLinkedCharFormat(SwCharFormat& rLink);
+    void SetLinkedCharFormat(SwCharFormat* pLink);
 
     const SwCharFormat* GetLinkedCharFormat() const;
 
diff --git a/sw/qa/core/doc/doc.cxx b/sw/qa/core/doc/doc.cxx
index 2ee2ee342bd3..8c882e906373 100644
--- a/sw/qa/core/doc/doc.cxx
+++ b/sw/qa/core/doc/doc.cxx
@@ -19,6 +19,7 @@
 #include <sfx2/viewfrm.hxx>
 #include <sfx2/dispatch.hxx>
 #include <vcl/scheduler.hxx>
+#include <comphelper/propertyvalue.hxx>
 
 #include <wrtsh.hxx>
 #include <fmtanchr.hxx>
@@ -271,6 +272,35 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, 
testCopyFlagSkipBookmarks)
     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), nActual);
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testLinkedStyleDelete)
+{
+    // Given a document with linked styles: myparastyle is linked to 
mycharstyle and vica versa:
+    createSwDoc();
+    uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> xParaStyle(
+        xFactory->createInstance("com.sun.star.style.ParagraphStyle"), 
uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> xCharStyle(
+        xFactory->createInstance("com.sun.star.style.CharacterStyle"), 
uno::UNO_QUERY);
+    uno::Reference<container::XNameContainer> 
xParaStyles(getStyles("ParagraphStyles"),
+                                                          uno::UNO_QUERY);
+    xParaStyles->insertByName("myparastyle", uno::Any(xParaStyle));
+    uno::Reference<container::XNameContainer> 
xCharStyles(getStyles("CharacterStyles"),
+                                                          uno::UNO_QUERY);
+    xCharStyles->insertByName("mycharstyle", uno::Any(xCharStyle));
+    xParaStyle->setPropertyValue("LinkStyle", 
uno::Any(OUString("mycharstyle")));
+    xCharStyle->setPropertyValue("LinkStyle", 
uno::Any(OUString("myparastyle")));
+
+    // When deleting the paragraph style (and only that):
+    xParaStyles->removeByName("myparastyle");
+
+    // Then make sure we don't crash on save:
+    uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+    uno::Sequence<beans::PropertyValue> aArgs = {
+        comphelper::makePropertyValue("FilterName", OUString("writer8")),
+    };
+    xStorable->storeAsURL(maTempFile.GetURL(), aArgs);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/doc/fmtcol.cxx b/sw/source/core/doc/fmtcol.cxx
index b2e66b7c4d31..6454a40581a2 100644
--- a/sw/source/core/doc/fmtcol.cxx
+++ b/sw/source/core/doc/fmtcol.cxx
@@ -113,6 +113,19 @@ SwTextFormatColl::~SwTextFormatColl()
 {
     if(m_bInSwFntCache)
         pSwFontCache->Delete( this );
+
+    if (GetDoc()->IsInDtor())
+    {
+        return;
+    }
+
+    for (const auto& pCharFormat : *GetDoc()->GetCharFormats())
+    {
+        if (pCharFormat->GetLinkedParaFormat() == this)
+        {
+            pCharFormat->SetLinkedParaFormat(nullptr);
+        }
+    }
 }
 void SwTextFormatColl::SwClientNotify(const SwModify& rModify, const SfxHint& 
rHint)
 {
@@ -316,7 +329,7 @@ void SwTextFormatColl::SwClientNotify(const SwModify& 
rModify, const SfxHint& rH
         SwFormatColl::SwClientNotify(rModify, rHint);
 }
 
-void SwTextFormatColl::SetLinkedCharFormat(SwCharFormat& rLink) { 
mpLinkedCharFormat = &rLink; }
+void SwTextFormatColl::SetLinkedCharFormat(SwCharFormat* pLink) { 
mpLinkedCharFormat = pLink; }
 
 const SwCharFormat* SwTextFormatColl::GetLinkedCharFormat() const { return 
mpLinkedCharFormat; }
 
diff --git a/sw/source/core/txtnode/chrfmt.cxx 
b/sw/source/core/txtnode/chrfmt.cxx
index 62544bc3dcfb..ea2bb5a45511 100644
--- a/sw/source/core/txtnode/chrfmt.cxx
+++ b/sw/source/core/txtnode/chrfmt.cxx
@@ -21,6 +21,7 @@
 
 #include <charfmt.hxx>
 #include <charformats.hxx>
+#include <doc.hxx>
 
 void SwCharFormat::dumpAsXml(xmlTextWriterPtr pWriter) const
 {
@@ -38,10 +39,26 @@ void SwCharFormat::dumpAsXml(xmlTextWriterPtr pWriter) const
     (void)xmlTextWriterEndElement(pWriter);
 }
 
-void SwCharFormat::SetLinkedParaFormat(SwTextFormatColl& rLink) { 
mpLinkedParaFormat = &rLink; }
+void SwCharFormat::SetLinkedParaFormat(SwTextFormatColl* pLink) { 
mpLinkedParaFormat = pLink; }
 
 const SwTextFormatColl* SwCharFormat::GetLinkedParaFormat() const { return 
mpLinkedParaFormat; }
 
+SwCharFormat::~SwCharFormat()
+{
+    if (GetDoc()->IsInDtor())
+    {
+        return;
+    }
+
+    for (const auto& pTextFormat : *GetDoc()->GetTextFormatColls())
+    {
+        if (pTextFormat->GetLinkedCharFormat() == this)
+        {
+            pTextFormat->SetLinkedCharFormat(nullptr);
+        }
+    }
+}
+
 void SwCharFormats::dumpAsXml(xmlTextWriterPtr pWriter) const
 {
     (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwCharFormats"));
diff --git a/sw/source/uibase/app/docstyle.cxx 
b/sw/source/uibase/app/docstyle.cxx
index ced5ec648606..f8cdfecd1249 100644
--- a/sw/source/uibase/app/docstyle.cxx
+++ b/sw/source/uibase/app/docstyle.cxx
@@ -744,7 +744,7 @@ void SwDocStyleSheet::SetLink(const OUString& rStr)
                 SwCharFormat* pLink = lcl_FindCharFormat(m_rDoc, rStr);
                 if (pLink)
                 {
-                    m_pColl->SetLinkedCharFormat(*pLink);
+                    m_pColl->SetLinkedCharFormat(pLink);
                 }
             }
             break;
@@ -756,7 +756,7 @@ void SwDocStyleSheet::SetLink(const OUString& rStr)
                 SwTextFormatColl* pLink = lcl_FindParaFormat(m_rDoc, rStr);
                 if (pLink)
                 {
-                    m_pCharFormat->SetLinkedParaFormat(*pLink);
+                    m_pCharFormat->SetLinkedParaFormat(pLink);
                 }
             }
             break;

Reply via email to