[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