diff options
author | Noel Grandin <noel.grandin@collabora.co.uk> | 2020-08-20 11:27:29 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2020-08-20 16:37:51 +0200 |
commit | 445cf499666f21c2d480ce1df9ce6004b9450b64 (patch) | |
tree | a9a085e5d8486176c6580261eaf686737927c4ac /svx | |
parent | 901add54cd5191b5a41ec11baddd669954c34025 (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>
Diffstat (limited to 'svx')
-rw-r--r-- | svx/source/svdraw/sdrpagewindow.cxx | 33 | ||||
-rw-r--r-- | svx/source/svdraw/svdpagv.cxx | 11 |
2 files changed, 32 insertions, 12 deletions
diff --git a/svx/source/svdraw/sdrpagewindow.cxx b/svx/source/svdraw/sdrpagewindow.cxx index 823205a22e65..0b0ea0536945 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 b95109ed6886..ad38d0ad3395 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,14 +291,14 @@ void SdrPageView::DrawLayer(SdrLayerID nID, OutputDevice* pGivenTarget, aTemporaryPaintWindow.SetRedrawRegion(rExistingRegion); else aTemporaryPaintWindow.SetRedrawRegion(vcl::Region(rRect)); - // patch the ExistingPageWindow - pPreparedTarget->patchPaintWindow(aTemporaryPaintWindow); + // patch the ExistingPageWindow + 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 { |