svx/source/svdraw/svdedxv.cxx | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-)
New commits: commit 74bb076ea1b7ab3645a1e0c25eca42d649e59937 Author: Andras Timar <[email protected]> AuthorDate: Thu Feb 26 13:46:51 2026 +0100 Commit: Miklos Vajna <[email protected]> CommitDate: Fri Feb 27 09:07:31 2026 +0100 svx: fix SIGSEGV in SdrEndTextEdit OutlinerView cleanup (LOKit multi-view) Fix a crash in VclReferenceBase::acquire() during SdrEndTextEdit's outliner view cleanup loop in multi-user LOKit Impress sessions. The window obtained from an OutlinerView could already be freed before VclPtr construction. Four fixes: - lcl_RemoveTextEditOutlinerViews: iterate backwards instead of forwards to avoid skipping entries when RemoveView shifts the array. Also use RemoveView by index instead of by pointer. - SdrEndTextEdit: hold pTEWin as VclPtr instead of raw pointer, so the text edit window stays alive after mpTextEditWin is cleared and until the SetCursor call. - SdrEndTextEdit cleanup loop: guard invalidation with a pWin->isDisposed() check, so we skip invalidation for windows that were destroyed during the orphan window between mxWeakTextEditObj clear and the cleanup loop. - DeleteDeviceFromPaintView: delete the OutlinerView after removing it from the outliner, fixing a memory leak. Change-Id: Ia8910efac9616df0c1e1f6597570a9a03fbe9a8d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200425 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx index 6cd139c86e6f..b55f2db11844 100644 --- a/svx/source/svdraw/svdedxv.cxx +++ b/svx/source/svdraw/svdedxv.cxx @@ -255,13 +255,14 @@ void lcl_RemoveTextEditOutlinerViews(SdrObjEditView const* pThis, SdrPageView co return; SdrOutliner* pOutliner = pView->GetTextEditOutliner(); - for (size_t nView = 0; nView < pOutliner->GetViewCount(); ++nView) + for (size_t nView = pOutliner->GetViewCount(); nView > 0;) { + nView--; OutlinerView* pOutlinerView = pOutliner->GetView(nView); if (pOutlinerView->GetWindow()->GetOutDev() != pOutputDevice) continue; - pOutliner->RemoveView(pOutlinerView); + pOutliner->RemoveView(nView); delete pOutlinerView; } }); @@ -1644,7 +1645,7 @@ SdrEndTextEditKind SdrObjEditView::SdrEndTextEdit(bool bDontDeleteReally) SdrEndTextEditKind eRet = SdrEndTextEditKind::Unchanged; rtl::Reference<SdrTextObj> pTEObj = mxWeakTextEditObj.get(); - vcl::Window* pTEWin = mpTextEditWin; + VclPtr<vcl::Window> pTEWin = mpTextEditWin; OutlinerView* pTEOutlinerView = mpTextEditOutlinerView; vcl::Cursor* pTECursorBuffer = m_pTextEditCursorBuffer; SdrUndoManager* pUndoEditUndoManager = nullptr; @@ -1863,17 +1864,20 @@ SdrEndTextEditKind SdrObjEditView::SdrEndTextEdit(bool bDontDeleteReally) // may not own the zeroth one delete pOLV; } - aRect.Union(m_aTextEditArea); - aRect.Union(m_aMinTextEditArea); - aRect = pWin->LogicToPixel(aRect); - aRect.AdjustLeft(-nMorePix); - aRect.AdjustTop(-nMorePix); - aRect.AdjustRight(nMorePix); - aRect.AdjustBottom(nMorePix); - aRect = pWin->PixelToLogic(aRect); - InvalidateOneWin(*pWin->GetOutDev(), aRect); - pWin->GetOutDev()->SetFillColor(); - pWin->GetOutDev()->SetLineColor(COL_BLACK); + if (pWin && !pWin->isDisposed()) + { + aRect.Union(m_aTextEditArea); + aRect.Union(m_aMinTextEditArea); + aRect = pWin->LogicToPixel(aRect); + aRect.AdjustLeft(-nMorePix); + aRect.AdjustTop(-nMorePix); + aRect.AdjustRight(nMorePix); + aRect.AdjustBottom(nMorePix); + aRect = pWin->PixelToLogic(aRect); + InvalidateOneWin(*pWin->GetOutDev(), aRect); + pWin->GetOutDev()->SetFillColor(); + pWin->GetOutDev()->SetLineColor(COL_BLACK); + } } // and now the Outliner itself if (!mbTextEditDontDelete) @@ -2596,6 +2600,7 @@ void SdrObjEditView::DeleteDeviceFromPaintView(OutputDevice& rOldDev) if (pOLV && pOLV->GetWindow() == rOldDev.GetOwnerWindow()) { mpTextEditOutliner->RemoveView(i); + delete pOLV; } } }
