From bce74af0eb8b9fff8c9b6b99c4a314d98f626570 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Mon, 23 Nov 2020 21:02:44 +0100 Subject: tdf#138253 sw textbox: fix content of draw format on undo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regression from commit da4f9b77a6cd39b1ae5babdd476d1575c8b9371c (tdf#135149 sw: fix deleting textbox of as-char shapes, 2020-09-07), the crash was caused by a user-after-free triggered from the X11 clipboard code. This could happen beause the clipboard document had a draw frame format, which has an SwNode pointer, but the SwNode instance was outside that clipboard document, and the owning document is already gone. So by the time the clipboard document would be deleted, the SwNodeIndex can't de-register itself. The root cause was that the doc model was corrupted after a cut of a textbox + undo: the textbox pointers of the fly/draw formats were OK, but not the SwFormatContent of the draw format. (cherry picked from commit 42e8e16cf93dcf944e5c1106f76aaa32057c0397) Conflicts: sw/source/core/layout/atrfrm.cxx Change-Id: I5761b72948caca397320aed801559e8493c33e1b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/106539 Tested-by: Jenkins Reviewed-by: Caolán McNamara --- sw/qa/core/undo/data/textbox-cut-undo.docx | Bin 0 -> 13196 bytes sw/qa/core/undo/undo.cxx | 34 +++++++++++++++++++++++++++++ sw/source/core/undo/undobj1.cxx | 7 ++++++ 3 files changed, 41 insertions(+) create mode 100644 sw/qa/core/undo/data/textbox-cut-undo.docx diff --git a/sw/qa/core/undo/data/textbox-cut-undo.docx b/sw/qa/core/undo/data/textbox-cut-undo.docx new file mode 100644 index 000000000000..35f0e857173e Binary files /dev/null and b/sw/qa/core/undo/data/textbox-cut-undo.docx differ diff --git a/sw/qa/core/undo/undo.cxx b/sw/qa/core/undo/undo.cxx index aeacffc78e9b..e43d154f3a66 100644 --- a/sw/qa/core/undo/undo.cxx +++ b/sw/qa/core/undo/undo.cxx @@ -10,11 +10,17 @@ #include #include +#include +#include #include #include #include #include +#include +#include +#include +#include char const DATA_DIRECTORY[] = "/sw/qa/core/undo/data/"; @@ -50,6 +56,34 @@ CPPUNIT_TEST_FIXTURE(SwCoreUndoTest, testTextboxCutSave) xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); } +CPPUNIT_TEST_FIXTURE(SwCoreUndoTest, testTextboxCutUndo) +{ + load(DATA_DIRECTORY, "textbox-cut-undo.docx"); + SwXTextDocument* pTextDoc = dynamic_cast(mxComponent.get()); + SwDocShell* pDocShell = pTextDoc->GetDocShell(); + SwWrtShell* pWrtShell = pDocShell->GetWrtShell(); + SwDoc* pDoc = pDocShell->GetDoc(); + SwView* pView = pDoc->GetDocShell()->GetView(); + + pView->GetViewFrame()->GetDispatcher()->Execute(FN_CNTNT_TO_NEXT_FRAME, SfxCallMode::SYNCHRON); + pView->StopShellTimer(); + rtl::Reference pTransfer = new SwTransferable(*pWrtShell); + pTransfer->Cut(); + SwFrameFormats& rSpzFrameFormats = *pDoc->GetSpzFrameFormats(); + CPPUNIT_ASSERT_EQUAL(static_cast(0), rSpzFrameFormats.size()); + + pWrtShell->Undo(); + CPPUNIT_ASSERT_EQUAL(static_cast(2), rSpzFrameFormats.size()); + + const SwNodeIndex* pIndex1 = rSpzFrameFormats[0]->GetContent().GetContentIdx(); + const SwNodeIndex* pIndex2 = rSpzFrameFormats[1]->GetContent().GetContentIdx(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 5 + // - Actual : 8 + // i.e. the draw frame format had a wrong node index in its content. + CPPUNIT_ASSERT_EQUAL(pIndex1->GetIndex(), pIndex2->GetIndex()); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/undobj1.cxx b/sw/source/core/undo/undobj1.cxx index 0f969713862a..2398ea8dad09 100644 --- a/sw/source/core/undo/undobj1.cxx +++ b/sw/source/core/undo/undobj1.cxx @@ -130,6 +130,13 @@ void SwUndoFlyBase::InsFly(::sw::UndoRedoContext & rContext, bool bShowSelFrame) pSdrObject->setUnoShape(nullptr); } } + if (m_pFrameFormat->Which() == RES_DRAWFRMFMT) + { + // This is a draw format and we just set the fly format's textbox pointer to this draw + // format. Sync the draw format's content with the fly format's content. + SwFrameFormat* pFlyFormat = m_pFrameFormat->GetOtherTextBoxFormat(); + m_pFrameFormat->SetFormatAttr(pFlyFormat->GetContent()); + } } m_pFrameFormat->MakeFrames(); -- cgit