From aea26546b80c38bf96c0a0418984460f7e4d284a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Fri, 13 Mar 2026 01:00:46 -0300 Subject: [PATCH] =?UTF-8?q?Fixed=20a=20rare=20crash=20provoked=20by=20two?= =?UTF-8?q?=20factors:=20*=20Fixed=20LSPDocumentClient::~LSPDocumentClient?= =?UTF-8?q?:=20It=20now=20explicitly=20calls=20`mDoc->unregisterClient(thi?= =?UTF-8?q?s);`.=20This=20ensures=20that=20whenever=20the=20client=20is=20?= =?UTF-8?q?destroyed=E2=80=94whether=20by=20the=20server=20shutting=20down?= =?UTF-8?q?=20or=20just=20the=20document=20closing=E2=80=94it=20cleanly=20?= =?UTF-8?q?detaches=20from=20the=20TextDocument.=20*=20Fixed=20`TextDocume?= =?UTF-8?q?nt::notifyDocumentClosed`=20Iterator=20Invalidation:=20Since=20?= =?UTF-8?q?`onDocumentClosed`=20is=20called=20during=20a=20loop=20over=20`?= =?UTF-8?q?mClients`,=20and=20`LSPDocumentClient`=20now=20unregisters=20it?= =?UTF-8?q?self=20during=20that=20exact=20same=20loop,=20it=20was=20modify?= =?UTF-8?q?ing=20the=20`mClients`=20`std::unordered=5Fset`=20while=20it=20?= =?UTF-8?q?was=20being=20iterated=20(which=20is=20undefined=20behavior).?= =?UTF-8?q?=20I=20changed=20`notifyDocumentClosed`=20to=20iterate=20over?= =?UTF-8?q?=20a=20copy=20of=20the=20clients,=20safely=20allowing=20clients?= =?UTF-8?q?=20to=20unregister=20themselves=20when=20they=20receive=20the?= =?UTF-8?q?=20notification.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/eepp/ui/doc/foldrangeservice.cpp | 4 +-- src/eepp/ui/doc/textdocument.cpp | 10 +++++-- src/eepp/ui/uicodeeditor.cpp | 29 +++++++++++++------ .../ecode/plugins/lsp/lspdocumentclient.cpp | 1 + 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/eepp/ui/doc/foldrangeservice.cpp b/src/eepp/ui/doc/foldrangeservice.cpp index 2c809fa03..34d1bb38d 100644 --- a/src/eepp/ui/doc/foldrangeservice.cpp +++ b/src/eepp/ui/doc/foldrangeservice.cpp @@ -281,14 +281,14 @@ bool FoldRangeService::isFoldingRegionInLine( Int64 docIdx ) { void FoldRangeService::shiftFoldingRegions( Int64 fromLine, Int64 numLines ) { Lock l( mMutex ); FoldingRegions foldingRegions; - + if ( numLines < 0 ) { Int64 removedLines = -numLines; Int64 toLine = fromLine + removedLines; for ( auto& foldingRegion : mFoldingRegions ) { auto& range = foldingRegion.second; - + if ( range.start().line() >= toLine ) { range.start().setLine( range.start().line() + numLines ); range.end().setLine( range.end().line() + numLines ); diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index 48f3a61ba..51f4d9ba0 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -4165,8 +4165,14 @@ void TextDocument::notifyDocumentSaved() { } void TextDocument::notifyDocumentClosed() { - Lock l( mClientsMutex ); - for ( auto& client : mClients ) { + std::vector clientsCopy; + { + Lock l( mClientsMutex ); + clientsCopy.reserve( mClients.size() ); + for ( auto& client : mClients ) + clientsCopy.push_back( client ); + } + for ( auto& client : clientsCopy ) { client->onDocumentClosed( this ); } } diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index 6f56918bd..45979eb60 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -5391,20 +5391,31 @@ bool UICodeEditor::stopMinimapDragging( const Vector2f& mousePos ) { return false; } +static void debounceFindRegions( UISceneNode* sceneNode, std::weak_ptr weakDoc, + Time refreshTime, String::HashType tag ) { + sceneNode->debounce( + [sceneNode, weakDoc, refreshTime, tag]() { + auto doc = weakDoc.lock(); + if ( doc ) { + if ( doc->getHighlighter()->isTokenizingAsync() ) { + debounceFindRegions( sceneNode, weakDoc, refreshTime, tag ); + } else { + doc->getFoldRangeService().findRegions(); + } + } + }, + refreshTime, tag ); +} + void UICodeEditor::findRegionsDelayed() { if ( !mDoc->getFoldRangeService().canFold() ) return; UISceneNode* sceneNode = getUISceneNode(); if ( sceneNode ) { - TextDocument* doc = mDoc.get(); - sceneNode->debounce( - [this, doc]() { - if ( doc->getHighlighter()->isTokenizingAsync() ) - findRegionsDelayed(); - else - doc->getFoldRangeService().findRegions(); - }, - mFoldsIsFirst ? Milliseconds( 100 ) : mFoldsRefreshTime, mTagFoldRange ); + std::weak_ptr weakDoc = mDoc; + debounceFindRegions( sceneNode, weakDoc, + mFoldsIsFirst ? Milliseconds( 100 ) : mFoldsRefreshTime, + mTagFoldRange ); mFoldsIsFirst = false; } diff --git a/src/tools/ecode/plugins/lsp/lspdocumentclient.cpp b/src/tools/ecode/plugins/lsp/lspdocumentclient.cpp index af1deabfe..0e99f9240 100644 --- a/src/tools/ecode/plugins/lsp/lspdocumentclient.cpp +++ b/src/tools/ecode/plugins/lsp/lspdocumentclient.cpp @@ -41,6 +41,7 @@ void LSPDocumentClient::setupFoldRangeService() { LSPDocumentClient::~LSPDocumentClient() { mDoc->getFoldRangeService().setProvider( nullptr ); + mDoc->unregisterClient( this ); mDoc = nullptr; UISceneNode* sceneNode = getUISceneNode(); if ( nullptr != sceneNode && 0 != mTag )