[kdevelop/kdevelop] kdevplatform/language/duchain: duchain: avoid reentrant import list use-after-free

Jarmo Tiitto <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 1031d1a66daa33b6ad84c28540c2e39948594998 by Jarmo Tiitto, on behalf of Volodymyr Zolotopupov.
Committed on 02/08/2026 at 13:13.
Pushed by jatothrim into branch 'master'.

duchain: avoid reentrant import list use-after-free

TopDUContextLocalPrivate iterated m_importedContexts directly while resolving each import.
Resolving an import can load another DUChain and rebuild its dynamic import structure,
which may append to the same m_importedContexts list reentrantly.
QList reallocation then invalidates the storage used by the active range-for loop,
leading to a use-after-free in IndexedDUContext::context() during clearImportedContextsRecursively().

M  +4    -2    kdevplatform/language/duchain/topducontext.cpp

https://invent.kde.org/kdevelop/kdevelop/-/commit/1031d1a66daa33b6ad84c28540c2e39948594998

diff --git a/kdevplatform/language/duchain/topducontext.cpp b/kdevplatform/language/duchain/topducontext.cpp
index f1526d694a..29bfa7a7fa 100644
--- a/kdevplatform/language/duchain/topducontext.cpp
+++ b/kdevplatform/language/duchain/topducontext.cpp
@@ -108,7 +108,8 @@ public:
         //Either we use some other contexts data and have no users, or we own the data and have users that share it.
         QMutexLocker lock(&importStructureMutex);
 
-        for (const DUContext::Import& import : std::as_const(m_importedContexts)) {
+        const auto importedContexts = m_importedContexts;
+        for (const DUContext::Import& import : importedContexts) {
             if (DUChain::self()->isInMemory(import.topContextIndex()) &&
                 dynamic_cast<TopDUContext*>(import.context(nullptr)))
                 dynamic_cast<TopDUContext*>(import.context(nullptr))->m_local->m_directImporters.remove(m_ctxt);
@@ -165,7 +166,8 @@ public:
 
         QSet<QPair<TopDUContext*, const TopDUContext*>> rebuild;
 
-        for (const DUContext::Import& import : std::as_const(m_importedContexts)) {
+        const auto importedContexts = m_importedContexts;
+        for (const DUContext::Import& import : importedContexts) {
             auto* top = dynamic_cast<TopDUContext*>(import.context(nullptr));
             if (top) {
                 top->m_local->m_directImporters.remove(m_ctxt);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.