sw/qa/core/unocore/unocore.cxx    |   53 ++++++++++++++++++++++++++++++++++++++
 sw/source/core/unocore/unoobj.cxx |    7 +++++
 2 files changed, 60 insertions(+)

New commits:
commit 440179cfce5aafa7f480bfea48984451553f8e84
Author:     László Németh <nem...@numbertext.org>
AuthorDate: Tue Jun 20 19:02:20 2023 +0200
Commit:     László Németh <nem...@numbertext.org>
CommitDate: Wed Jun 21 10:55:19 2023 +0200

    tdf#155951 sw: fix crash using XTextRange::getString() in selectionChanged()
    
    XTextRange::getString() triggered selection change event,
    resulting infinite recursion, when getString() used
    in selectionChanged() of the listener.
    
    Steps to reproduce (used by the unit test, too):
    
    Add a XSelectionChangeListener to the document with a
    selectionChanged() calling the getString() of the selected
    text range. Select a word in the document editor using
    the Ctrl-Shift-arrow keys.
    
    Change-Id: I87a0f60cee3663f5303d6eb6980058ccdcc373e1
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153356
    Tested-by: Jenkins
    Reviewed-by: László Németh <nem...@numbertext.org>
    (cherry picked from commit 0534715608aad7cc68f83ad4b72d8be0a35d0d6f)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153345

diff --git a/sw/qa/core/unocore/unocore.cxx b/sw/qa/core/unocore/unocore.cxx
index a1e931e75fb4..199da2e72a79 100644
--- a/sw/qa/core/unocore/unocore.cxx
+++ b/sw/qa/core/unocore/unocore.cxx
@@ -15,6 +15,8 @@
 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
 #include <com/sun/star/text/XDependentTextField.hpp>
 #include <com/sun/star/document/XDocumentInsertable.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
 
 #include <comphelper/propertyvalue.hxx>
 #include <comphelper/sequenceashashmap.hxx>
@@ -912,6 +914,57 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, 
testConvertToTextFrame)
     CPPUNIT_ASSERT_EQUAL(aPaM.GetPoint()->nNode, aFrame3Anchor);
 }
 
+namespace
+{
+/// This selection listener calls XTextRange::getString() on a selection 
change, which triggered
+/// a new selection change event by accident, resulting infinite recursion and 
crash
+struct SelectionChangeListener : public 
cppu::WeakImplHelper<view::XSelectionChangeListener>
+{
+public:
+    SelectionChangeListener();
+    // view::XSelectionChangeListener
+    void SAL_CALL selectionChanged(const lang::EventObject& rEvent) override;
+
+    // lang::XEventListener
+    void SAL_CALL disposing(const lang::EventObject& rSource) override;
+};
+}
+
+SelectionChangeListener::SelectionChangeListener() {}
+
+void SelectionChangeListener::selectionChanged(const lang::EventObject& rEvent)
+{
+    uno::Reference<view::XSelectionSupplier> xSelectionSupplier(rEvent.Source, 
uno::UNO_QUERY);
+    css::uno::Reference<css::container::XIndexAccess> 
xSelection(xSelectionSupplier->getSelection(),
+                                                                 
css::uno::UNO_QUERY_THROW);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSelection->getCount());
+    css::uno::Reference<css::text::XTextRange> 
xTextRange(xSelection->getByIndex(0),
+                                                          
css::uno::UNO_QUERY_THROW);
+    CPPUNIT_ASSERT(xTextRange->getString().startsWith("test"));
+}
+
+void SelectionChangeListener::disposing(const lang::EventObject& /*rSource*/) 
{}
+
+CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testTdf155951)
+{
+    createSwDoc();
+    uno::Reference<text::XTextDocument> xTextDocument(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<text::XText> xText = xTextDocument->getText();
+    uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+    xText->insertString(xCursor, "test", /*bAbsorb=*/false);
+
+    uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
+    uno::Reference<view::XSelectionSupplier> 
xController(xModel->getCurrentController(),
+                                                         uno::UNO_QUERY);
+    xController->addSelectionChangeListener(new SelectionChangeListener());
+
+    // This crashed here because of infinite recursion
+    dispatchCommand(mxComponent, ".uno:WordLeftSel", {});
+
+    // this needs to wait for dispatching (trigger also a second selection 
change)
+    xText->insertString(xCursor, "test", /*bAbsorb=*/false);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/unocore/unoobj.cxx 
b/sw/source/core/unocore/unoobj.cxx
index 2e65cf97bfcd..ccbcc536a75e 100644
--- a/sw/source/core/unocore/unoobj.cxx
+++ b/sw/source/core/unocore/unoobj.cxx
@@ -74,6 +74,8 @@
 #include <comphelper/propertyvalue.hxx>
 #include <comphelper/servicehelper.hxx>
 #include <comphelper/profilezone.hxx>
+#include <comphelper/flagguard.hxx>
+#include <swmodule.hxx>
 
 using namespace ::com::sun::star;
 
@@ -158,6 +160,11 @@ void SwUnoCursorHelper::GetTextFromPam(SwPaM & rPam, 
OUString & rBuffer,
     const bool bOldShowProgress = xWrt->m_bShowProgress;
     xWrt->m_bShowProgress = false;
     xWrt->m_bHideDeleteRedlines = pLayout && pLayout->IsHideRedlines();
+    // tdf#155951 SwWriter::Write calls EndAllAction, and that
+    // called SelectShell(), triggering selection change event, which
+    // resulted infinite recursion, if selectionChanged() calls
+    // XTextRange::getString() e.g. on the selected range.
+    ::comphelper::FlagRestorationGuard g(g_bNoInterrupt, true);
 
     if( ! aWriter.Write( xWrt ).IsError() )
     {

Reply via email to