summaryrefslogtreecommitdiff
path: root/svx
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2020-08-20 11:27:29 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2020-08-27 12:50:25 +0200
commit39f42fbd3f91afad60dad2937d2dfed79b956485 (patch)
tree56855b5b4daa6324527142404c17b2cf6b438ed8 /svx
parent892329fc88116cbe70f0d92f8d307775840595b4 (diff)
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@collabora.co.uk> (cherry picked from commit 445cf499666f21c2d480ce1df9ce6004b9450b64) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101450
Diffstat (limited to 'svx')
-rw-r--r--svx/source/svdraw/sdrpagewindow.cxx33
-rw-r--r--svx/source/svdraw/svdpagv.cxx11
2 files changed, 32 insertions, 12 deletions
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
{