[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);