[Libreoffice-commits] core.git: Branch 'libreoffice-7-0' - include/svx svx/source sw/source

Noel Grandin (via logerrit) logerrit at kemper.freedesktop.org
Thu Aug 27 10:51:00 UTC 2020


 include/svx/sdrpagewindow.hxx       |    4 ++--
 svx/source/svdraw/sdrpagewindow.cxx |   33 ++++++++++++++++++++++++++-------
 svx/source/svdraw/svdpagv.cxx       |   11 ++++++-----
 sw/source/core/view/viewsh.cxx      |    5 +++--
 4 files changed, 37 insertions(+), 16 deletions(-)

New commits:
commit 39f42fbd3f91afad60dad2937d2dfed79b956485
Author:     Noel Grandin <noel.grandin at collabora.co.uk>
AuthorDate: Thu Aug 20 11:27:29 2020 +0200
Commit:     Noel Grandin <noel.grandin at collabora.co.uk>
CommitDate: Thu Aug 27 12:50:25 2020 +0200

    tdf#132940 Crash in mergedlo!vcl::Region::operator=
    
    We had a SdrPageWindow accessing a SdPaintWindow that had already been
    freed.
    Turns that SdrPageWindow can be "patched" more than once given enough
    stuff going on in writer, so make the call sites restore the previous
    state as the stack unwinds.
    
    Change-Id: Ia1ef5c9b2f818b7873e8e739c9cdf257554e403a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101044
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>
    (cherry picked from commit 445cf499666f21c2d480ce1df9ce6004b9450b64)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101450

diff --git a/include/svx/sdrpagewindow.hxx b/include/svx/sdrpagewindow.hxx
index 80417a6729a0..f5cb98c297da 100644
--- a/include/svx/sdrpagewindow.hxx
+++ b/include/svx/sdrpagewindow.hxx
@@ -68,8 +68,8 @@ public:
     rtl::Reference< sdr::overlay::OverlayManager > const & GetOverlayManager() const;
 
     // #i72752# allow patcing SdrPaintWindow from SdrPageView::DrawLayer if needed
-    void patchPaintWindow(SdrPaintWindow& rPaintWindow);
-    void unpatchPaintWindow();
+    [[nodiscard]] SdrPaintWindow* patchPaintWindow(SdrPaintWindow& rPaintWindow);
+    void unpatchPaintWindow(SdrPaintWindow* pPreviousPaintWindow);
 
     // the repaint method. For migration from pPaintProc, use one more parameter
     void PrePaint();
diff --git a/svx/source/svdraw/sdrpagewindow.cxx b/svx/source/svdraw/sdrpagewindow.cxx
index fb3155c0eb14..6d197dab5282 100644
--- a/svx/source/svdraw/sdrpagewindow.cxx
+++ b/svx/source/svdraw/sdrpagewindow.cxx
@@ -163,22 +163,41 @@ rtl::Reference< sdr::overlay::OverlayManager > const & SdrPageWindow::GetOverlay
     return GetPaintWindow().GetOverlayManager();
 }
 
-void SdrPageWindow::patchPaintWindow(SdrPaintWindow& rPaintWindow)
+SdrPaintWindow* SdrPageWindow::patchPaintWindow(SdrPaintWindow& rPaintWindow)
 {
-    mpImpl->mpOriginalPaintWindow = mpImpl->mpPaintWindow;
-    mpImpl->mpPaintWindow = &rPaintWindow;
-    mpImpl->mpOriginalPaintWindow->setPatched(&rPaintWindow);
+    if (!mpImpl->mpOriginalPaintWindow)
+    {
+        // first patch
+        mpImpl->mpOriginalPaintWindow = mpImpl->mpPaintWindow;
+        mpImpl->mpPaintWindow = &rPaintWindow;
+        mpImpl->mpOriginalPaintWindow->setPatched(&rPaintWindow);
+        return mpImpl->mpOriginalPaintWindow;
+    }
+    else
+    {
+        // second or more patch
+        auto pPreviousPaintWindow = mpImpl->mpPaintWindow;
+        mpImpl->mpPaintWindow = &rPaintWindow;
+        mpImpl->mpOriginalPaintWindow->setPatched(&rPaintWindow);
+        return pPreviousPaintWindow;
+    }
 }
 
-void SdrPageWindow::unpatchPaintWindow()
+void SdrPageWindow::unpatchPaintWindow(SdrPaintWindow* pPreviousPaintWindow)
 {
-    DBG_ASSERT(mpImpl->mpOriginalPaintWindow, "SdrPageWindow::unpatchPaintWindow: paint window not patched!" );
-    if (mpImpl->mpOriginalPaintWindow)
+    if (pPreviousPaintWindow == mpImpl->mpOriginalPaintWindow)
     {
+        // first patch
         mpImpl->mpPaintWindow = mpImpl->mpOriginalPaintWindow;
         mpImpl->mpOriginalPaintWindow->setPatched(nullptr);
         mpImpl->mpOriginalPaintWindow = nullptr;
     }
+    else
+    {
+        // second or more patch
+        mpImpl->mpPaintWindow = pPreviousPaintWindow;
+        mpImpl->mpOriginalPaintWindow->setPatched(pPreviousPaintWindow);
+    }
 }
 
 void SdrPageWindow::PrePaint()
diff --git a/svx/source/svdraw/svdpagv.cxx b/svx/source/svdraw/svdpagv.cxx
index 215e37bc7c94..480182782984 100644
--- a/svx/source/svdraw/svdpagv.cxx
+++ b/svx/source/svdraw/svdpagv.cxx
@@ -32,6 +32,7 @@
 #include <svx/sdrpagewindow.hxx>
 #include <svx/sdrpaintwindow.hxx>
 #include <comphelper/lok.hxx>
+#include <comphelper/scopeguard.hxx>
 #include <basegfx/range/b2irectangle.hxx>
 
 using namespace ::com::sun::star;
@@ -290,13 +291,13 @@ void SdrPageView::DrawLayer(SdrLayerID nID, OutputDevice* pGivenTarget,
                     else
                         aTemporaryPaintWindow.SetRedrawRegion(vcl::Region(rRect));
                     // patch the ExistingPageWindow
-                    pPreparedTarget->patchPaintWindow(aTemporaryPaintWindow);
-
+                    auto pPreviousWindow = pPreparedTarget->patchPaintWindow(aTemporaryPaintWindow);
+                    // unpatch window when leaving the scope
+                    const ::comphelper::ScopeGuard aGuard(
+                        [&pPreviousWindow, &pPreparedTarget]() { pPreparedTarget->unpatchPaintWindow(pPreviousWindow); } );
+                    
                     // redraw the layer
                     pPreparedTarget->RedrawLayer(&nID, pRedirector, pPageFrame);
-
-                    // restore the ExistingPageWindow
-                    pPreparedTarget->unpatchPaintWindow();
                 }
                 else
                 {
diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx
index c5d20fe38d88..ff036d9b9014 100644
--- a/sw/source/core/view/viewsh.cxx
+++ b/sw/source/core/view/viewsh.cxx
@@ -1716,6 +1716,7 @@ class RenderContextGuard
 {
     std::unique_ptr<SdrPaintWindow> m_TemporaryPaintWindow;
     SdrPageWindow* m_pPatchedPageWindow;
+    SdrPaintWindow* m_pPreviousPaintWindow = nullptr;
 
 public:
     RenderContextGuard(VclPtr<vcl::RenderContext>& pRef, vcl::RenderContext* pValue, SwViewShell* pShell)
@@ -1738,7 +1739,7 @@ public:
                     if (nullptr != m_pPatchedPageWindow)
                     {
                         m_TemporaryPaintWindow.reset(new SdrPaintWindow(*pDrawView, *pValue));
-                        m_pPatchedPageWindow->patchPaintWindow(*m_TemporaryPaintWindow);
+                        m_pPreviousPaintWindow = m_pPatchedPageWindow->patchPaintWindow(*m_TemporaryPaintWindow);
                     }
                 }
             }
@@ -1749,7 +1750,7 @@ public:
     {
         if(nullptr != m_pPatchedPageWindow)
         {
-            m_pPatchedPageWindow->unpatchPaintWindow();
+            m_pPatchedPageWindow->unpatchPaintWindow(m_pPreviousPaintWindow);
         }
     }
 };


More information about the Libreoffice-commits mailing list