[Lldb-commits] [lldb] [lldb] Avoid interning SBStream contents into the ConstString Pool (PR #227338)
Ebuka Ezike via lldb-commits
lldb-commits at lists.llvm.org
Tue Sep 29 08:02:49 PDT 2026
https://github.com/da-viper created https://github.com/llvm/llvm-project/pull/227338
SBStream::GetData() builds a ConstString from the stream's contents before returning a const char*. ConstString's backing StringPool is global and never frees entries, so every call permanently adds a copy of the stream's contents to the pool for the lifetime of the debugger.
lldb-dap's telemetry dispatcher uses `SetFromJSON` to send the telemetry to the debugger. This keeps growing the pool with data that will never be used again. From https://github.com/llvm/llvm-project/pull/225785
Add a private SBStream::GetString(), returning the underlying StreamString's contents as an llvm::StringRef without touching the ConstString pool.
>From 28527c9ea54da2dab9d003432d843790ea94edc6 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <e_ezike at apple.com>
Date: Tue, 29 Sep 2026 15:52:18 +0100
Subject: [PATCH] [lldb] Avoid interning SBStream contents into the global
ConstString pool
SBStream::GetData() builds a ConstString from the stream's contents
before returning a const char*. ConstString's backing StringPool is
global and never frees entries, so every call permanently adds a copy
of the stream's contents to the pool for the lifetime of the debugger.
lldb-dap's telemetry dispatcher uses SetFromJSON to send the telemetry
to the debugger. This keeps growing the pool with data that will never
be used again.
Add a private SBStream::GetString(), returning the underlying
StreamString's contents as an llvm::StringRef without touching the
ConstString pool.
---
lldb/include/lldb/API/SBStream.h | 7 +++++++
lldb/source/API/SBCommandInterpreter.cpp | 2 +-
lldb/source/API/SBStream.cpp | 10 ++++++++++
lldb/source/API/SBStructuredData.cpp | 4 ++--
lldb/source/API/SBTypeSummary.cpp | 3 ++-
5 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/lldb/include/lldb/API/SBStream.h b/lldb/include/lldb/API/SBStream.h
index 1ba375b600df6..8be99034690aa 100644
--- a/lldb/include/lldb/API/SBStream.h
+++ b/lldb/include/lldb/API/SBStream.h
@@ -17,6 +17,10 @@ namespace lldb_private {
class ScriptInterpreter;
} // namespace lldb_private
+namespace llvm {
+class StringRef;
+} // namespace llvm
+
namespace lldb {
class LLDB_API SBStream {
@@ -73,6 +77,7 @@ class LLDB_API SBStream {
friend class SBBreakpointLocation;
friend class SBBreakpointName;
friend class SBCommandReturnObject;
+ friend class SBCommandInterpreter;
friend class SBCompileUnit;
friend class SBData;
friend class SBDebugger;
@@ -105,6 +110,7 @@ class LLDB_API SBStream {
friend class SBTypeEnumMember;
friend class SBTypeMemberFunction;
friend class SBTypeMember;
+ friend class SBTypeSummary;
friend class SBValue;
friend class SBWatchpoint;
@@ -119,6 +125,7 @@ class LLDB_API SBStream {
private:
SBStream(const SBStream &) = delete;
const SBStream &operator=(const SBStream &) = delete;
+ llvm::StringRef GetString() const;
std::unique_ptr<lldb_private::Stream> m_opaque_up;
bool m_is_file = false;
};
diff --git a/lldb/source/API/SBCommandInterpreter.cpp b/lldb/source/API/SBCommandInterpreter.cpp
index 57c6ae375c0ac..f86da6509f9fa 100644
--- a/lldb/source/API/SBCommandInterpreter.cpp
+++ b/lldb/source/API/SBCommandInterpreter.cpp
@@ -221,7 +221,7 @@ void SBCommandInterpreter::HandleCommandsFromFile(
if (!file.IsValid()) {
SBStream s;
file.GetDescription(s);
- result->AppendErrorWithFormat("File is not valid: %s", s.GetData());
+ result->AppendErrorWithFormatv("File is not valid: {}", s.GetString());
}
FileSpec tmp_spec = file.ref();
diff --git a/lldb/source/API/SBStream.cpp b/lldb/source/API/SBStream.cpp
index 128ee6b50b232..863b3b3f8849b 100644
--- a/lldb/source/API/SBStream.cpp
+++ b/lldb/source/API/SBStream.cpp
@@ -194,3 +194,13 @@ void SBStream::Clear() {
static_cast<StreamString *>(m_opaque_up.get())->Clear();
}
}
+
+/// Exists so friend classes can use data without putting it in
+// the ConstString pool.
+llvm::StringRef SBStream::GetString() const {
+ if (m_is_file || m_opaque_up == nullptr)
+ return llvm::StringRef{};
+
+ auto *stream_raw = static_cast<StreamString *>(m_opaque_up.get());
+ return stream_raw->GetString();
+}
diff --git a/lldb/source/API/SBStructuredData.cpp b/lldb/source/API/SBStructuredData.cpp
index 25e229e972873..182baeb75942a 100644
--- a/lldb/source/API/SBStructuredData.cpp
+++ b/lldb/source/API/SBStructuredData.cpp
@@ -86,8 +86,8 @@ lldb::SBError SBStructuredData::SetFromJSON(lldb::SBStream &stream) {
lldb::SBError error;
- StructuredData::ObjectSP json_obj =
- StructuredData::ParseJSON(stream.GetData());
+ llvm::StringRef stream_data = stream.GetString();
+ StructuredData::ObjectSP json_obj = StructuredData::ParseJSON(stream_data);
m_impl_up->SetObjectSP(json_obj);
static constexpr StructuredDataType unsupported_type[] = {
diff --git a/lldb/source/API/SBTypeSummary.cpp b/lldb/source/API/SBTypeSummary.cpp
index a424394d2768f..1d153b073e753 100644
--- a/lldb/source/API/SBTypeSummary.cpp
+++ b/lldb/source/API/SBTypeSummary.cpp
@@ -162,7 +162,8 @@ SBTypeSummary SBTypeSummary::CreateWithCallback(FormatCallback cb,
SBTypeSummaryOptions options(opt);
if (!cb(sb_value, options, stream))
return false;
- stm.Write(stream.GetData(), stream.GetSize());
+ llvm::StringRef sdata = stream.GetString();
+ stm.Write(sdata.data(), sdata.size());
return true;
},
description ? description : "callback summary formatter")));
More information about the lldb-commits
mailing list