[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
Wed Oct 7 08:48:32 PDT 2026
https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/227338
>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 1/2] [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")));
>From 089ee9d238bd71523b873feb0b24e47c8fbcb0ce Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Wed, 7 Oct 2026 16:48:02 +0100
Subject: [PATCH 2/2] Use const char *
---
lldb/include/lldb/API/SBStream.h | 6 +-----
lldb/source/API/SBCommandInterpreter.cpp | 2 +-
lldb/source/API/SBStream.cpp | 12 ++++++------
3 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/lldb/include/lldb/API/SBStream.h b/lldb/include/lldb/API/SBStream.h
index 8be99034690aa..58a716eee4038 100644
--- a/lldb/include/lldb/API/SBStream.h
+++ b/lldb/include/lldb/API/SBStream.h
@@ -17,10 +17,6 @@ namespace lldb_private {
class ScriptInterpreter;
} // namespace lldb_private
-namespace llvm {
-class StringRef;
-} // namespace llvm
-
namespace lldb {
class LLDB_API SBStream {
@@ -125,7 +121,7 @@ class LLDB_API SBStream {
private:
SBStream(const SBStream &) = delete;
const SBStream &operator=(const SBStream &) = delete;
- llvm::StringRef GetString() const;
+ const char *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 f86da6509f9fa..df0ea153c0011 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->AppendErrorWithFormatv("File is not valid: {}", s.GetString());
+ result->AppendErrorWithFormat("File is not valid: %s", s.GetString());
}
FileSpec tmp_spec = file.ref();
diff --git a/lldb/source/API/SBStream.cpp b/lldb/source/API/SBStream.cpp
index 863b3b3f8849b..fbc4aba4b1fc6 100644
--- a/lldb/source/API/SBStream.cpp
+++ b/lldb/source/API/SBStream.cpp
@@ -195,12 +195,12 @@ void SBStream::Clear() {
}
}
-/// Exists so friend classes can use data without putting it in
-// the ConstString pool.
-llvm::StringRef SBStream::GetString() const {
+/// Exists so friend classes can use the StringString's data without
+/// putting it in the ConstString pool.
+const char *SBStream::GetString() const {
if (m_is_file || m_opaque_up == nullptr)
- return llvm::StringRef{};
+ return nullptr;
- auto *stream_raw = static_cast<StreamString *>(m_opaque_up.get());
- return stream_raw->GetString();
+ const auto *stream_raw = static_cast<StreamString *>(m_opaque_up.get());
+ return stream_raw->GetString().data();
}
More information about the lldb-commits
mailing list