tdf#147485 sw: fix group shape crash using std::shared_ptr

for SwFrameFormat::m_pOtherTextBoxeFormats.
Before there was broken manual handling of this
member, resulting random crashes.

Details: Writer textboxes are textframe + shape
pairs. Accordingly the shape has a draw format,
the frame has a fly format. In case of group
shapes the paired structure doesn't work, because
there is one shape format and many fly formats.
To handle this there is a class (SwTextBoxNode)
which has a small frame format table inside.
This cache gives the possibility to handle
each frame shape pairs inside the group depending
on what SdrObject owns that textbox.

However there is another place where these formats
stored, namely the SpzFrameFormatTable in SwDoc.
The only problem is that, when a flyframe removed,
it has to be deleted from both tables, but if the
DelLayoutFormat() is called, that will call the
~FrameFormat(), and if the format already deleted
from the SwTextBoxNode, there will be double deleting
for the same address, which caused the crash.

To avoid this the following is present:

When fly deletion occurs, first the format is
deleted from the doc, then via the ~SwFrameFomat()
will be deleted from the TextBoxNode. If the deleted
format is a drawing, the whole node will be destructed
via the shared_ptr. Hopefully that will be fine,
without any leak.

Change-Id: I007724695bc035998cb35efeefecd308aae36e85
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132308
Reviewed-by: László Németh <nemeth@numbertext.org>
Tested-by: László Németh <nemeth@numbertext.org>
diff --git a/sw/inc/frmfmt.hxx b/sw/inc/frmfmt.hxx
index 12795bf..4a5f2f1 100644
--- a/sw/inc/frmfmt.hxx
+++ b/sw/inc/frmfmt.hxx
@@ -74,7 +74,7 @@ class SW_DLLPUBLIC SwFrameFormat
    // The assigned SwFrmFmt list.
    SwFrameFormats *m_ffList;

    SwTextBoxNode* m_pOtherTextBoxFormat;
    std::shared_ptr< SwTextBoxNode > m_pOtherTextBoxFormats;

    struct change_name
    {
@@ -102,8 +102,8 @@ protected:

public:

    SwTextBoxNode* GetOtherTextBoxFormat() const { return m_pOtherTextBoxFormat; };
    void SetOtherTextBoxFormat(SwTextBoxNode* pNew) { m_pOtherTextBoxFormat = pNew; };
    const std::shared_ptr< SwTextBoxNode >& GetOtherTextBoxFormats() const { return m_pOtherTextBoxFormats; };
    void SetOtherTextBoxFormats(const std::shared_ptr<SwTextBoxNode>& rNew) { m_pOtherTextBoxFormats = rNew; };

    virtual ~SwFrameFormat() override;

diff --git a/sw/inc/textboxhelper.hxx b/sw/inc/textboxhelper.hxx
index 3881d89..d851a0f 100644
--- a/sw/inc/textboxhelper.hxx
+++ b/sw/inc/textboxhelper.hxx
@@ -213,7 +213,7 @@ public:
    ~SwTextBoxNode();

    // default copy ctor is enough
    SwTextBoxNode(SwTextBoxNode&) = default;
    SwTextBoxNode(const SwTextBoxNode&) = default;

    // This method adds a textbox entry to the shape
    // Parameters:
@@ -224,7 +224,12 @@ public:
    // This will remove the textbox entry.
    // Parameters:
    //     pDrawObject: The shape which have the textbox to be deleted.
    void DelTextBox(const SdrObject* pDrawObject);
    void DelTextBox(const SdrObject* pDrawObject, bool bDelFromDoc = false);

    // This will remove the textbox entry.
    // Parameters:
    //     pTextBox: The textbox what have to be deleted.
    void DelTextBox(const SwFrameFormat* pTextBox, bool bDelFromDoc = false);

    // This will return with the frame format of the textbox what belongs
    // to the given shape (pDrawObject)
diff --git a/sw/qa/extras/ooxmlexport/data/Tdf147485.docx b/sw/qa/extras/ooxmlexport/data/Tdf147485.docx
new file mode 100644
index 0000000..cb630ef
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/Tdf147485.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
index 8ee4c8c3..fa0199e 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
@@ -837,6 +837,12 @@ CPPUNIT_TEST_FIXTURE(SwModelTestBase, testSemiTransparentText)
    CPPUNIT_ASSERT_EQUAL(nTransparence, nActual);
}

CPPUNIT_TEST_FIXTURE(SwModelTestBase, testTdf147485)
{
    // Before the fix this was impossible.
    load(DATA_DIRECTORY, "Tdf147485.docx");
}

CPPUNIT_TEST_FIXTURE(SwModelTestBase, testUserField)
{
    // Create an in-memory empty document with a user field.
diff --git a/sw/source/core/doc/DocumentLayoutManager.cxx b/sw/source/core/doc/DocumentLayoutManager.cxx
index c67e9e0..006501b 100644
--- a/sw/source/core/doc/DocumentLayoutManager.cxx
+++ b/sw/source/core/doc/DocumentLayoutManager.cxx
@@ -464,11 +464,11 @@ SwFrameFormat *DocumentLayoutManager::CopyLayoutFormat(
        pDest->MakeFrames();

    // If the draw format has a TextBox, then copy its fly format as well.
    if (rSource.Which() == RES_DRAWFRMFMT && rSource.GetOtherTextBoxFormat())
    if (rSource.Which() == RES_DRAWFRMFMT && rSource.GetOtherTextBoxFormats())
    {
        auto pObj = rSource.FindRealSdrObject();
        auto pTextBoxNd = new SwTextBoxNode(pDest);
        pDest->SetOtherTextBoxFormat(pTextBoxNd);
        auto pTextBoxNd = std::make_shared<SwTextBoxNode>(SwTextBoxNode(pDest));
        pDest->SetOtherTextBoxFormats(pTextBoxNd);

        if (pObj)
        {
@@ -515,7 +515,7 @@ SwFrameFormat *DocumentLayoutManager::CopyLayoutFormat(
                        && pNewObj->getChildrenOfSdrObject()->GetObj(it))
                        pNewObj = pNewObj->getChildrenOfSdrObject()->GetObj(it);
                    pTextBoxNd->AddTextBox(pNewObj, pDestTextBox);
                    pDestTextBox->SetOtherTextBoxFormat(pTextBoxNd);
                    pDestTextBox->SetOtherTextBoxFormats(pTextBoxNd);
                }

                if (!bIsGroupObj)
diff --git a/sw/source/core/doc/docdraw.cxx b/sw/source/core/doc/docdraw.cxx
index 6445ab7..cd1883e 100644
--- a/sw/source/core/doc/docdraw.cxx
+++ b/sw/source/core/doc/docdraw.cxx
@@ -225,7 +225,7 @@ SwDrawContact* SwDoc::GroupSelection( SdrView& rDrawView )
#endif
            // Before the format will be killed, save its textbox for later use.
            if (auto pShapeFormat = pContact->GetFormat())
                if (auto pTextBoxNode = pShapeFormat->GetOtherTextBoxFormat())
                if (auto pTextBoxNode = pShapeFormat->GetOtherTextBoxFormats())
                    for (const auto& rTextBoxElement : pTextBoxNode->GetAllTextBoxes())
                        vSavedTextBoxes.emplace(rTextBoxElement);

@@ -255,14 +255,15 @@ SwDrawContact* SwDoc::GroupSelection( SdrView& rDrawView )
            text::PositionLayoutDir::PositionInLayoutDirOfAnchor );

        // Add the saved textboxes to the new format.
        auto pTextBoxNode = new SwTextBoxNode(pFormat);
        auto pTextBoxNode = std::make_shared<SwTextBoxNode>(
            SwTextBoxNode(static_cast<SwFrameFormat*>(pFormat)));
        for (const auto& pTextBoxEntry : vSavedTextBoxes)
        {
            pTextBoxNode->AddTextBox(const_cast<SdrObject*>(pTextBoxEntry.first),
                                     pTextBoxEntry.second);
            pTextBoxEntry.second->SetOtherTextBoxFormat(pTextBoxNode);
            pTextBoxEntry.second->SetOtherTextBoxFormats(pTextBoxNode);
        }
        pFormat->SetOtherTextBoxFormat(pTextBoxNode);
        pFormat->SetOtherTextBoxFormats(pTextBoxNode);
        vSavedTextBoxes.clear();

        rDrawView.GroupMarked();
@@ -302,7 +303,7 @@ SwDrawContact* SwDoc::GroupSelection( SdrView& rDrawView )
    return pNewContact;
}

static void lcl_CollectTextBoxesForSubGroupObj(SwFrameFormat* pTargetFormat, SwTextBoxNode* pTextBoxNode,
static void lcl_CollectTextBoxesForSubGroupObj(SwFrameFormat* pTargetFormat, std::shared_ptr<SwTextBoxNode> pTextBoxNode,
                                               SdrObject* pSourceObjs)
{
    if (auto pChildrenObjs = pSourceObjs->getChildrenOfSdrObject())
@@ -312,12 +313,12 @@ static void lcl_CollectTextBoxesForSubGroupObj(SwFrameFormat* pTargetFormat, SwT
    {
        if (auto pTextBox = pTextBoxNode->GetTextBox(pSourceObjs))
        {
            if (!pTargetFormat->GetOtherTextBoxFormat())
            if (!pTargetFormat->GetOtherTextBoxFormats())
            {
                pTargetFormat->SetOtherTextBoxFormat(new SwTextBoxNode(pTargetFormat));
                pTargetFormat->SetOtherTextBoxFormats(std::make_shared<SwTextBoxNode>(SwTextBoxNode(pTargetFormat)));
            }
            pTargetFormat->GetOtherTextBoxFormat()->AddTextBox(pSourceObjs, pTextBox);
            pTextBox->SetOtherTextBoxFormat(pTargetFormat->GetOtherTextBoxFormat());
            pTargetFormat->GetOtherTextBoxFormats()->AddTextBox(pSourceObjs, pTextBox);
            pTextBox->SetOtherTextBoxFormats(pTargetFormat->GetOtherTextBoxFormats());
        }
    }
}
@@ -351,9 +352,9 @@ void SwDoc::UnGroupSelection( SdrView& rDrawView )
                {
                    SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));

                    SwTextBoxNode* pTextBoxNode = nullptr;
                    std::shared_ptr<SwTextBoxNode> pTextBoxNode;
                    if (auto pGroupFormat = pContact->GetFormat())
                        pTextBoxNode = pGroupFormat->GetOtherTextBoxFormat();
                        pTextBoxNode = pGroupFormat->GetOtherTextBoxFormats();

                    SwFormatAnchor aAnch( pContact->GetFormat()->GetAnchor() );
                    SdrObjList *pLst = pObjGroup->GetSubList();
@@ -378,10 +379,10 @@ void SwDoc::UnGroupSelection( SdrView& rDrawView )
                            {
                                if (auto pTextBoxFormat = pTextBoxNode->GetTextBox(pSubObj))
                                {
                                    auto pNewTextBoxNode = new SwTextBoxNode(pFormat);
                                    auto pNewTextBoxNode =std::make_shared<SwTextBoxNode>(SwTextBoxNode(pFormat));
                                    pNewTextBoxNode->AddTextBox(pSubObj, pTextBoxFormat);
                                    pFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
                                    pTextBoxFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
                                    pFormat->SetOtherTextBoxFormats(pNewTextBoxNode);
                                    pTextBoxFormat->SetOtherTextBoxFormats(pNewTextBoxNode);
                                }
                            }
                            else
diff --git a/sw/source/core/doc/textboxhelper.cxx b/sw/source/core/doc/textboxhelper.cxx
index 50af58a..74d29aa 100644
--- a/sw/source/core/doc/textboxhelper.cxx
+++ b/sw/source/core/doc/textboxhelper.cxx
@@ -69,7 +69,7 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape, SdrObject* pObject, bool bCo
    const bool bIsGroupObj = dynamic_cast<SdrObjGroup*>(pObject->getParentSdrObjectFromSdrObject());

    // If TextBox wasn't enabled previously
    if (pShape->GetOtherTextBoxFormat() && pShape->GetOtherTextBoxFormat()->GetTextBox(pObject))
    if (pShape->GetOtherTextBoxFormats() && pShape->GetOtherTextBoxFormats()->GetTextBox(pObject))
        return;

    // Store the current text content of the shape
@@ -115,19 +115,19 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape, SdrObject* pObject, bool bCo
    assert(nullptr != dynamic_cast<SwDrawFrameFormat*>(pShape));
    assert(nullptr != dynamic_cast<SwFlyFrameFormat*>(pFormat));

    if (!pShape->GetOtherTextBoxFormat())
    if (!pShape->GetOtherTextBoxFormats())
    {
        auto* pTextBox = new SwTextBoxNode(pShape);
        auto pTextBox = std::make_shared<SwTextBoxNode>(SwTextBoxNode(pShape));
        pTextBox->AddTextBox(pObject, pFormat);
        pShape->SetOtherTextBoxFormat(pTextBox);
        pFormat->SetOtherTextBoxFormat(pTextBox);
        pShape->SetOtherTextBoxFormats(pTextBox);
        pFormat->SetOtherTextBoxFormats(pTextBox);
    }
    else
    {
        auto* pTextBox = pShape->GetOtherTextBoxFormat();
        auto pTextBox = pShape->GetOtherTextBoxFormats();
        pTextBox->AddTextBox(pObject, pFormat);
        pShape->SetOtherTextBoxFormat(pTextBox);
        pFormat->SetOtherTextBoxFormat(pTextBox);
        pShape->SetOtherTextBoxFormats(pTextBox);
        pFormat->SetOtherTextBoxFormats(pTextBox);
    }
    // Initialize properties.
    uno::Reference<beans::XPropertySet> xPropertySet(xTextFrame, uno::UNO_QUERY);
@@ -222,7 +222,7 @@ void SwTextBoxHelper::set(SwFrameFormat* pShapeFormat, SdrObject* pObj,
        return;
    std::vector<std::pair<beans::Property, uno::Any>> aOldProps;
    // If there is a format, check if the shape already has a textbox assigned to.
    if (auto pTextBoxNode = pShapeFormat->GetOtherTextBoxFormat())
    if (auto pTextBoxNode = pShapeFormat->GetOtherTextBoxFormats())
    {
        // If it has a texbox, destroy it.
        if (pTextBoxNode->GetTextBox(pObj))
@@ -251,16 +251,16 @@ void SwTextBoxHelper::set(SwFrameFormat* pShapeFormat, SdrObject* pObj,
        }
        // And set the new one.
        pTextBoxNode->AddTextBox(pObj, pFormat);
        pFormat->SetOtherTextBoxFormat(pTextBoxNode);
        pFormat->SetOtherTextBoxFormats(pTextBoxNode);
    }
    else
    {
        // If the shape do not have a texbox node and textbox,
        // create that for the shape.
        auto* pTextBox = new SwTextBoxNode(pShapeFormat);
        auto pTextBox = std::shared_ptr<SwTextBoxNode>(new SwTextBoxNode(pShapeFormat));
        pTextBox->AddTextBox(pObj, pFormat);
        pShapeFormat->SetOtherTextBoxFormat(pTextBox);
        pFormat->SetOtherTextBoxFormat(pTextBox);
        pShapeFormat->SetOtherTextBoxFormats(pTextBox);
        pFormat->SetOtherTextBoxFormats(pTextBox);
    }
    // Initialize its properties
    uno::Reference<beans::XPropertySet> xPropertySet(xNew, uno::UNO_QUERY);
@@ -336,14 +336,14 @@ void SwTextBoxHelper::set(SwFrameFormat* pShapeFormat, SdrObject* pObj,
void SwTextBoxHelper::destroy(const SwFrameFormat* pShape, const SdrObject* pObject)
{
    // If a TextBox was enabled previously
    auto pTextBox = pShape->GetOtherTextBoxFormat();
    auto pTextBox = pShape->GetOtherTextBoxFormats();
    if (pTextBox && pTextBox->IsTextBoxActive(pObject))
    {
        // Unlink the TextBox's text range from the original shape.
        pTextBox->SetTextBoxInactive(pObject);

        // Delete the associated TextFrame.
        pTextBox->DelTextBox(pObject);
        pTextBox->DelTextBox(pObject, true);
    }
}

@@ -355,7 +355,7 @@ bool SwTextBoxHelper::isTextBox(const SwFrameFormat* pFormat, sal_uInt16 nType,
    if (!pFormat || pFormat->Which() != nType)
        return false;

    auto pTextBox = pFormat->GetOtherTextBoxFormat();
    auto pTextBox = pFormat->GetOtherTextBoxFormats();
    if (!pTextBox)
        return false;

@@ -474,14 +474,14 @@ SwFrameFormat* SwTextBoxHelper::getOtherTextBoxFormat(const SwFrameFormat* pForm
    if (nType == RES_DRAWFRMFMT)
    {
        if (pObject)
            return pFormat->GetOtherTextBoxFormat()->GetTextBox(pObject);
            return pFormat->GetOtherTextBoxFormats()->GetTextBox(pObject);
        if (pFormat->FindRealSdrObject())
            return pFormat->GetOtherTextBoxFormat()->GetTextBox(pFormat->FindRealSdrObject());
            return pFormat->GetOtherTextBoxFormats()->GetTextBox(pFormat->FindRealSdrObject());
        return nullptr;
    }
    if (nType == RES_FLYFRMFMT)
    {
        return pFormat->GetOtherTextBoxFormat()->GetOwnerShape();
        return pFormat->GetOtherTextBoxFormats()->GetOwnerShape();
    }
    return nullptr;
}
@@ -1633,13 +1633,7 @@ SwTextBoxNode::SwTextBoxNode(SwFrameFormat* pOwnerShape)
        m_pTextBoxes.clear();
}

SwTextBoxNode::~SwTextBoxNode()
{
    m_pTextBoxes.clear();

    if (m_pOwnerShapeFormat && m_pOwnerShapeFormat->GetOtherTextBoxFormat())
        m_pOwnerShapeFormat->SetOtherTextBoxFormat(nullptr);
}
SwTextBoxNode::~SwTextBoxNode() { m_pTextBoxes.clear(); }

void SwTextBoxNode::AddTextBox(SdrObject* pDrawObject, SwFrameFormat* pNewTextBox)
{
@@ -1660,7 +1654,7 @@ void SwTextBoxNode::AddTextBox(SdrObject* pDrawObject, SwFrameFormat* pNewTextBo
    m_pTextBoxes.push_back(aElem);
}

void SwTextBoxNode::DelTextBox(const SdrObject* pDrawObject)
void SwTextBoxNode::DelTextBox(const SdrObject* pDrawObject, bool bDelFromDoc)
{
    assert(pDrawObject);
    if (m_pTextBoxes.empty())
@@ -1670,10 +1664,46 @@ void SwTextBoxNode::DelTextBox(const SdrObject* pDrawObject)
    {
        if (it->m_pDrawObject == pDrawObject)
        {
            m_pOwnerShapeFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat(
                it->m_pTextBoxFormat);
            it = m_pTextBoxes.erase(it);
            break;
            if (bDelFromDoc)
            {
                m_pOwnerShapeFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat(
                    it->m_pTextBoxFormat);
                // What about m_pTextBoxes? So, when the DelLayoutFormat() removes the format
                // then the ~SwFrameFormat() will call this method again to remove the entry.
                break;
            }
            else
            {
                it = m_pTextBoxes.erase(it);
                break;
            }
        }
        ++it;
    }
}

void SwTextBoxNode::DelTextBox(const SwFrameFormat* pTextBox, bool bDelFromDoc)
{
    if (m_pTextBoxes.empty())
        return;

    for (auto it = m_pTextBoxes.begin(); it != m_pTextBoxes.end();)
    {
        if (it->m_pTextBoxFormat == pTextBox)
        {
            if (bDelFromDoc)
            {
                m_pOwnerShapeFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat(
                    it->m_pTextBoxFormat);
                // What about m_pTextBoxes? So, when the DelLayoutFormat() removes the format
                // then the ~SwFrameFormat() will call this method again to remove the entry.
                break;
            }
            else
            {
                it = m_pTextBoxes.erase(it);
                break;
            }
        }
        ++it;
    }
diff --git a/sw/source/core/draw/dcontact.cxx b/sw/source/core/draw/dcontact.cxx
index f698309..54e1567 100644
--- a/sw/source/core/draw/dcontact.cxx
+++ b/sw/source/core/draw/dcontact.cxx
@@ -1342,7 +1342,7 @@ void SwDrawContact::Changed_( const SdrObject& rObj,
            // tdf#135198: keep text box together with its shape
            const SwPageFrame* rPageFrame = pAnchoredDrawObj->GetPageFrame();
            if (rPageFrame && rPageFrame->isFrameAreaPositionValid() && GetFormat()
                && GetFormat()->GetOtherTextBoxFormat())
                && GetFormat()->GetOtherTextBoxFormats())
            {
                SwDoc* const pDoc = GetFormat()->GetDoc();

diff --git a/sw/source/core/layout/atrfrm.cxx b/sw/source/core/layout/atrfrm.cxx
index e3f1934..7db55da 100644
--- a/sw/source/core/layout/atrfrm.cxx
+++ b/sw/source/core/layout/atrfrm.cxx
@@ -2520,8 +2520,7 @@ SwFrameFormat::SwFrameFormat(
    sal_uInt16 nFormatWhich,
    const WhichRangesContainer& pWhichRange)
:   SwFormat(rPool, pFormatNm, pWhichRange, pDrvdFrame, nFormatWhich),
    m_ffList(nullptr),
    m_pOtherTextBoxFormat(nullptr)
    m_ffList(nullptr)
{
}

@@ -2532,8 +2531,7 @@ SwFrameFormat::SwFrameFormat(
    sal_uInt16 nFormatWhich,
    const WhichRangesContainer& pWhichRange)
:   SwFormat(rPool, rFormatNm, pWhichRange, pDrvdFrame, nFormatWhich),
    m_ffList(nullptr),
    m_pOtherTextBoxFormat(nullptr)
    m_ffList(nullptr)
{
}

@@ -2548,24 +2546,15 @@ SwFrameFormat::~SwFrameFormat()
        }
    }

    if( nullptr == m_pOtherTextBoxFormat )
    if( nullptr == m_pOtherTextBoxFormats )
        return;

    auto pObj = FindRealSdrObject();
    if (Which() == RES_FLYFRMFMT && pObj)
    {
        // This is a fly-frame-format just delete this
        // textbox entry from the draw-frame-format.
        m_pOtherTextBoxFormat->DelTextBox(pObj);
    }
    // This is a fly-frame-format just delete this
    // textbox entry from the textbox collection.
    if (Which() == RES_FLYFRMFMT)
        m_pOtherTextBoxFormats->DelTextBox(this);

    if (Which() == RES_DRAWFRMFMT)
    {
        // This format is the owner shape, so its time
        // to del the textbox node.
        delete m_pOtherTextBoxFormat;
        m_pOtherTextBoxFormat = nullptr;
    }
    m_pOtherTextBoxFormats.reset();
}

void SwFrameFormat::SetName( const OUString& rNewName, bool bBroadcast )
@@ -2884,9 +2873,9 @@ void SwFrameFormat::dumpAsXml(xmlTextWriterPtr pWriter) const
    if (pWhich)
        (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("which"), BAD_CAST(pWhich));

    if (m_pOtherTextBoxFormat)
    if (m_pOtherTextBoxFormats)
    {
        (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("OtherTextBoxFormat"), "%p", m_pOtherTextBoxFormat);
        (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("OtherTextBoxFormat"), "%p", m_pOtherTextBoxFormats.get());
    }

    GetAttrSet().dumpAsXml(pWriter);
diff --git a/sw/source/core/text/porfly.cxx b/sw/source/core/text/porfly.cxx
index f287727..8a4b8be 100644
--- a/sw/source/core/text/porfly.cxx
+++ b/sw/source/core/text/porfly.cxx
@@ -364,7 +364,7 @@ void SwFlyCntPortion::SetBase( const SwTextFrame& rFrame, const Point &rBase,

    if (auto pFormat = FindFrameFormat(pSdrObj))
    {
        if (pFormat->GetOtherTextBoxFormat())
        if (pFormat->GetOtherTextBoxFormats())
        {
            const bool bModified = pFormat->GetDoc()->getIDocumentState().IsEnableSetModified();
            pFormat->GetDoc()->getIDocumentState().SetEnableSetModified(false);
diff --git a/sw/source/core/undo/undobj1.cxx b/sw/source/core/undo/undobj1.cxx
index fa88f61..8463118 100644
--- a/sw/source/core/undo/undobj1.cxx
+++ b/sw/source/core/undo/undobj1.cxx
@@ -55,9 +55,9 @@ SwUndoFlyBase::~SwUndoFlyBase()
{
    if( m_bDelFormat )       // delete during an Undo?
    {
        if (m_pFrameFormat->GetOtherTextBoxFormat())
        if (m_pFrameFormat->GetOtherTextBoxFormats())
        {   // clear that before delete
            m_pFrameFormat->SetOtherTextBoxFormat(nullptr);
            m_pFrameFormat->SetOtherTextBoxFormats(nullptr);
        }
        delete m_pFrameFormat;
    }
@@ -138,19 +138,19 @@ void SwUndoFlyBase::InsFly(::sw::UndoRedoContext & rContext, bool bShowSelFrame)
        pCNd->GetTextNode()->InsertItem(aFormat, m_nContentPos, m_nContentPos, SetAttrMode::NOHINTEXPAND);
    }

    if (m_pFrameFormat->GetOtherTextBoxFormat())
    if (m_pFrameFormat->GetOtherTextBoxFormats())
    {
        // recklessly assume that this thing will live longer than the
        // SwUndoFlyBase - not sure what could be done if that isn't the case...
        m_pFrameFormat->GetOtherTextBoxFormat()->GetOwnerShape()->SetOtherTextBoxFormat(
            m_pFrameFormat->GetOtherTextBoxFormat());
        m_pFrameFormat->GetOtherTextBoxFormats()->GetOwnerShape()->SetOtherTextBoxFormats(
            m_pFrameFormat->GetOtherTextBoxFormats());

        SdrObject* pSdrObject
            = m_pFrameFormat->GetOtherTextBoxFormat()->GetOwnerShape()->FindSdrObject();
            = m_pFrameFormat->GetOtherTextBoxFormats()->GetOwnerShape()->FindSdrObject();
        if (pSdrObject && m_pFrameFormat->Which() == RES_FLYFRMFMT)
            m_pFrameFormat->GetOtherTextBoxFormat()->AddTextBox(pSdrObject, m_pFrameFormat);
            m_pFrameFormat->GetOtherTextBoxFormats()->AddTextBox(pSdrObject, m_pFrameFormat);

        if (m_pFrameFormat->GetOtherTextBoxFormat()->GetOwnerShape()->Which() == RES_DRAWFRMFMT)
        if (m_pFrameFormat->GetOtherTextBoxFormats()->GetOwnerShape()->Which() == RES_DRAWFRMFMT)
        {

            if (pSdrObject)
@@ -163,7 +163,7 @@ void SwUndoFlyBase::InsFly(::sw::UndoRedoContext & rContext, bool bShowSelFrame)
        }
        if (m_pFrameFormat->Which() == RES_FLYFRMFMT)
        {
            SwFrameFormat* pShapeFormat = m_pFrameFormat->GetOtherTextBoxFormat()->GetOwnerShape();
            SwFrameFormat* pShapeFormat = m_pFrameFormat->GetOtherTextBoxFormats()->GetOwnerShape();
            pShapeFormat->SetFormatAttr(m_pFrameFormat->GetContent());
        }
    }
@@ -207,9 +207,9 @@ void SwUndoFlyBase::DelFly( SwDoc* pDoc )
    m_bDelFormat = true;                 // delete Format in DTOR
    m_pFrameFormat->DelFrames();                 // destroy Frames

    if (m_pFrameFormat->GetOtherTextBoxFormat())
    if (m_pFrameFormat->GetOtherTextBoxFormats())
    {   // tdf#108867 clear that pointer
        m_pFrameFormat->GetOtherTextBoxFormat()->GetOwnerShape()->SetOtherTextBoxFormat(nullptr);
        m_pFrameFormat->GetOtherTextBoxFormats()->GetOwnerShape()->SetOtherTextBoxFormats(nullptr);
    }

    // all Uno objects should now log themselves off
diff --git a/sw/source/core/undo/undraw.cxx b/sw/source/core/undo/undraw.cxx
index 94146fe..f316858 100644
--- a/sw/source/core/undo/undraw.cxx
+++ b/sw/source/core/undo/undraw.cxx
@@ -199,7 +199,7 @@ void SwUndoDrawGroup::UndoImpl(::sw::UndoRedoContext &)

    // This will store the textboxes what were owned by this group
    std::vector<std::pair<SdrObject*, SwFrameFormat*>> vTextBoxes;
    if (auto pOldTextBoxNode = pFormat->GetOtherTextBoxFormat())
    if (auto pOldTextBoxNode = pFormat->GetOtherTextBoxFormats())
    {
        if (auto pChildren = pObj->getChildrenOfSdrObject())
        {
@@ -240,10 +240,10 @@ void SwUndoDrawGroup::UndoImpl(::sw::UndoRedoContext &)
        {
            if (rElem.first == pObj)
            {
                auto pNewTextBoxNode = new SwTextBoxNode(rSave.pFormat);
                rSave.pFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
                auto pNewTextBoxNode = std::make_shared<SwTextBoxNode>(SwTextBoxNode(rSave.pFormat));
                rSave.pFormat->SetOtherTextBoxFormats(pNewTextBoxNode);
                pNewTextBoxNode->AddTextBox(rElem.first, rElem.second);
                rElem.second->SetOtherTextBoxFormat(pNewTextBoxNode);
                rElem.second->SetOtherTextBoxFormats(pNewTextBoxNode);
                break;
            }
        }
@@ -278,7 +278,7 @@ void SwUndoDrawGroup::RedoImpl(::sw::UndoRedoContext &)
        SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));

        // Save the textboxes
        if (auto pOldTextBoxNode = rSave.pFormat->GetOtherTextBoxFormat())
        if (auto pOldTextBoxNode = rSave.pFormat->GetOtherTextBoxFormats())
        {
            if (auto pTextBox = pOldTextBoxNode->GetTextBox(pObj))
                vTextBoxes.push_back(std::pair(pObj, pTextBox));
@@ -310,13 +310,13 @@ void SwUndoDrawGroup::RedoImpl(::sw::UndoRedoContext &)
    // Restore the textboxes
    if (vTextBoxes.size())
    {
        auto pNewTextBoxNode = new SwTextBoxNode(m_pObjArray[0].pFormat);
        auto pNewTextBoxNode = std::make_shared<SwTextBoxNode>(SwTextBoxNode(m_pObjArray[0].pFormat));
        for (auto& rElem : vTextBoxes)
        {
            pNewTextBoxNode->AddTextBox(rElem.first, rElem.second);
            rElem.second->SetOtherTextBoxFormat(pNewTextBoxNode);
            rElem.second->SetOtherTextBoxFormats(pNewTextBoxNode);
        }
        m_pObjArray[0].pFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
        m_pObjArray[0].pFormat->SetOtherTextBoxFormats(pNewTextBoxNode);
    }

    // #i45952# - notify that position attributes are already set
@@ -401,7 +401,7 @@ void SwUndoDrawUnGroup::UndoImpl(::sw::UndoRedoContext & rContext)
        ::lcl_SaveAnchor( rSave.pFormat, rSave.nNodeIdx );

        // copy the textboxes for later use to this vector
        if (auto pTxBxNd = rSave.pFormat->GetOtherTextBoxFormat())
        if (auto pTxBxNd = rSave.pFormat->GetOtherTextBoxFormats())
        {
            if (auto pGroupObj = m_pObjArray[0].pObj)
            {
@@ -436,13 +436,13 @@ void SwUndoDrawUnGroup::UndoImpl(::sw::UndoRedoContext & rContext)
    // Restore the vector content for the new formats
    if (vTextBoxes.size())
    {
        auto pNewTxBxNd = new SwTextBoxNode(m_pObjArray[0].pFormat);
        auto pNewTxBxNd = std::make_shared<SwTextBoxNode>( SwTextBoxNode(m_pObjArray[0].pFormat));
        for (auto& rElem : vTextBoxes)
        {
            pNewTxBxNd->AddTextBox(rElem.first, rElem.second);
            rElem.second->SetOtherTextBoxFormat(pNewTxBxNd);
            rElem.second->SetOtherTextBoxFormats(pNewTxBxNd);
        }
        m_pObjArray[0].pFormat->SetOtherTextBoxFormat(pNewTxBxNd);
        m_pObjArray[0].pFormat->SetOtherTextBoxFormats(pNewTxBxNd);
    }


@@ -466,7 +466,7 @@ void SwUndoDrawUnGroup::RedoImpl(::sw::UndoRedoContext &)

    // Store the textboxes in this vector for later use.
    std::vector<std::pair<SdrObject*, SwFrameFormat*>> vTextBoxes;
    if (auto pTextBoxNode = pFormat->GetOtherTextBoxFormat())
    if (auto pTextBoxNode = pFormat->GetOtherTextBoxFormats())
    {
        auto pMasterObj = m_pObjArray[0].pObj;

@@ -498,10 +498,10 @@ void SwUndoDrawUnGroup::RedoImpl(::sw::UndoRedoContext &)
        {
            if (pElem.first == rSave.pObj)
            {
                auto pTmpTxBxNd = new SwTextBoxNode(rSave.pFormat);
                auto pTmpTxBxNd = std::make_shared<SwTextBoxNode>(SwTextBoxNode(rSave.pFormat));
                pTmpTxBxNd->AddTextBox(rSave.pObj, pElem.second);
                pFormat->SetOtherTextBoxFormat(pTmpTxBxNd);
                pElem.second->SetOtherTextBoxFormat(pTmpTxBxNd);
                pFormat->SetOtherTextBoxFormats(pTmpTxBxNd);
                pElem.second->SetOtherTextBoxFormats(pTmpTxBxNd);
                break;
            }
        }