Author: Michael Buch Date: 2024-08-20T18:40:54+01:00 New Revision: 770cd24140038646539602406fff54497793dae8
URL: https://github.com/llvm/llvm-project/commit/770cd24140038646539602406fff54497793dae8 DIFF: https://github.com/llvm/llvm-project/commit/770cd24140038646539602406fff54497793dae8.diff LOG: [lldb][ClangExpressionParser] Don't leak memory when multiplexing ExternalASTSources (#104799) When we use `SemaSourceWithPriorities` as the `ASTContext`s ExternalASTSource, we allocate a `ClangASTSourceProxy` (via `CreateProxy`) and two `ExternalASTSourceWrapper`. Then we push these sources into a vector in `SemaSourceWithPriorities`. The allocated `SemaSourceWithPriorities` itself will get properly deallocated because the `ASTContext` wraps it in an `IntrusiveRefCntPtr`. But the three sources we allocated earlier will never get released. This patch fixes this by mimicking what `MultiplexExternalSemaSource` does (which is what `SemaSourceWithPriorities` is based on anyway). I.e., when `SemaSourceWithPriorities` gets constructed, it increments the use count of its sources. And on destruction it decrements them. Similarly, to make sure we dealloacted the `ClangASTProxy` properly, the `ExternalASTSourceWrapper` now assumes shared ownership of the underlying source. Added: Modified: lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp Removed: ################################################################################ diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp index a95fce1c5aa966..5d67a51b269051 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp @@ -18,7 +18,10 @@ lldb_private::ASTConsumerForwarder::~ASTConsumerForwarder() = default; void lldb_private::ASTConsumerForwarder::PrintStats() { m_c->PrintStats(); } -lldb_private::SemaSourceWithPriorities::~SemaSourceWithPriorities() = default; +lldb_private::SemaSourceWithPriorities::~SemaSourceWithPriorities() { + for (auto *Source : Sources) + Source->Release(); +} void lldb_private::SemaSourceWithPriorities::PrintStats() { for (size_t i = 0; i < Sources.size(); ++i) diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h index 79ed74b79f04fd..44e52e8dd65113 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h @@ -14,6 +14,7 @@ #include "clang/Sema/MultiplexExternalSemaSource.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaConsumer.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include <optional> namespace clang { @@ -24,13 +25,15 @@ class Module; namespace lldb_private { -/// Wraps an ExternalASTSource into an ExternalSemaSource. Doesn't take -/// ownership of the provided source. +/// Wraps an ExternalASTSource into an ExternalSemaSource. +/// +/// Assumes shared ownership of the underlying source. class ExternalASTSourceWrapper : public clang::ExternalSemaSource { - ExternalASTSource *m_Source; + llvm::IntrusiveRefCntPtr<ExternalASTSource> m_Source; public: - ExternalASTSourceWrapper(ExternalASTSource *Source) : m_Source(Source) { + explicit ExternalASTSourceWrapper(ExternalASTSource *Source) + : m_Source(Source) { assert(m_Source && "Can't wrap nullptr ExternalASTSource"); } @@ -256,10 +259,18 @@ class SemaSourceWithPriorities : public clang::ExternalSemaSource { /// Construct a SemaSourceWithPriorities with a 'high quality' source that /// has the higher priority and a 'low quality' source that will be used /// as a fallback. - SemaSourceWithPriorities(clang::ExternalSemaSource &high_quality_source, - clang::ExternalSemaSource &low_quality_source) { - Sources.push_back(&high_quality_source); - Sources.push_back(&low_quality_source); + /// + /// This class assumes shared ownership of the sources provided to it. + SemaSourceWithPriorities(clang::ExternalSemaSource *high_quality_source, + clang::ExternalSemaSource *low_quality_source) { + assert(high_quality_source); + assert(low_quality_source); + + high_quality_source->Retain(); + low_quality_source->Retain(); + + Sources.push_back(high_quality_source); + Sources.push_back(low_quality_source); } ~SemaSourceWithPriorities() override; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index c441153d1efb05..d37787ebae26c3 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -1224,15 +1224,15 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, clang::ExternalASTSource *ast_source = decl_map->CreateProxy(); if (ast_context.getExternalSource()) { - auto module_wrapper = + auto *module_wrapper = new ExternalASTSourceWrapper(ast_context.getExternalSource()); - auto ast_source_wrapper = new ExternalASTSourceWrapper(ast_source); + auto *ast_source_wrapper = new ExternalASTSourceWrapper(ast_source); - auto multiplexer = - new SemaSourceWithPriorities(*module_wrapper, *ast_source_wrapper); - IntrusiveRefCntPtr<ExternalASTSource> Source(multiplexer); - ast_context.setExternalSource(Source); + auto *multiplexer = + new SemaSourceWithPriorities(module_wrapper, ast_source_wrapper); + + ast_context.setExternalSource(multiplexer); } else { ast_context.setExternalSource(ast_source); } _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits