[Lldb-commits] [lldb] [lldb] Trim and show embedded zeros in `charN_t` arrays (PR #195514)

via lldb-commits lldb-commits at lists.llvm.org
Sun May 3 03:24:22 PDT 2026


https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/195514

>From 581ad0090434ac9a534f656c6ad56fdd59f28a01 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Sun, 3 May 2026 11:55:47 +0200
Subject: [PATCH] [lldb] Trim and show embedded zeros in `char*_t` arrays

---
 .../lldb/DataFormatters/StringPrinter.h       |  7 +++++++
 lldb/source/DataFormatters/StringPrinter.cpp  | 12 +++++++++++
 .../Language/CPlusPlus/CxxStringTypes.cpp     | 20 +++++++++++++++++++
 .../API/lang/cpp/char1632_t/TestChar1632T.py  |  6 ++++++
 lldb/test/API/lang/cpp/char1632_t/main.cpp    |  8 +++++++-
 .../API/lang/cpp/char8_t/TestCxxChar8_t.py    | 12 +++++++++++
 lldb/test/API/lang/cpp/char8_t/main.cpp       |  3 +++
 .../API/lang/cpp/wchar_t/TestCxxWCharT.py     |  3 +++
 lldb/test/API/lang/cpp/wchar_t/main.cpp       |  8 ++++++--
 9 files changed, 76 insertions(+), 3 deletions(-)

diff --git a/lldb/include/lldb/DataFormatters/StringPrinter.h b/lldb/include/lldb/DataFormatters/StringPrinter.h
index 4169f53e63f38..0f013564c5999 100644
--- a/lldb/include/lldb/DataFormatters/StringPrinter.h
+++ b/lldb/include/lldb/DataFormatters/StringPrinter.h
@@ -62,6 +62,10 @@ class StringPrinter {
 
     bool GetBinaryZeroIsTerminator() const { return m_zero_is_terminator; }
 
+    void SetTrimTrailingZeros(bool v) { m_trim_trailing_zeros = v; }
+
+    bool GetTrimTrailingZeros() const { return m_trim_trailing_zeros; }
+
     void SetEscapeNonPrintables(bool e) { m_escape_non_printables = e; }
 
     bool GetEscapeNonPrintables() const { return m_escape_non_printables; }
@@ -95,6 +99,9 @@ class StringPrinter {
     /// True iff a zero bytes ('\0') should terminate the memory region that
     /// is being dumped.
     bool m_zero_is_terminator = true;
+    /// True iff trailing zero bytes should be stripped from the string.
+    /// Mutually exclusive with `m_zero_is_terminator`.
+    bool m_trim_trailing_zeros = false;
     /// The language-specific style for escaping special characters.
     EscapeStyle m_escape_style = EscapeStyle::CXX;
   };
diff --git a/lldb/source/DataFormatters/StringPrinter.cpp b/lldb/source/DataFormatters/StringPrinter.cpp
index 60cb0fc5d6876..a61042b34d29b 100644
--- a/lldb/source/DataFormatters/StringPrinter.cpp
+++ b/lldb/source/DataFormatters/StringPrinter.cpp
@@ -280,6 +280,11 @@ static bool DumpEncodedBufferToStream(
     const SourceDataType *data_end_ptr = data_ptr + source_size;
 
     const bool zero_is_terminator = dump_options.GetBinaryZeroIsTerminator();
+    const bool trim_trailing_zeros = dump_options.GetTrimTrailingZeros();
+
+    assert((!zero_is_terminator || !trim_trailing_zeros) &&
+           "BinaryZeroIsTerminator and "
+           "TrimTrailingZeros are mutually exclusive");
 
     if (zero_is_terminator) {
       while (data_ptr < data_end_ptr) {
@@ -291,6 +296,12 @@ static bool DumpEncodedBufferToStream(
       }
 
       data_ptr = (const SourceDataType *)data.GetDataStart();
+    } else if (trim_trailing_zeros) {
+      while (data_end_ptr != data_ptr) {
+        if (*(data_end_ptr - 1))
+          break;
+        data_end_ptr--;
+      }
     }
 
     lldb::WritableDataBufferSP utf8_data_buffer_sp;
@@ -385,6 +396,7 @@ lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStreamOptions::
   SetQuote(options.GetQuote());
   SetEscapeNonPrintables(options.GetEscapeNonPrintables());
   SetBinaryZeroIsTerminator(options.GetBinaryZeroIsTerminator());
+  SetTrimTrailingZeros(options.GetTrimTrailingZeros());
   SetEscapeStyle(options.GetEscapeStyle());
 }
 
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp
index bf8c393445908..f78613861424b 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp
@@ -60,6 +60,16 @@ static bool CharStringSummaryProvider(ValueObject &valobj, Stream &stream) {
   options.SetStream(&stream);
   options.SetPrefixToken(getElementTraits(ElemType).first);
 
+  CompilerType ty = valobj.GetCompilerType();
+  uint64_t size = 0;
+  if (ty.IsArrayType(nullptr, &size) && size > 0) {
+    options.SetSourceSize(size);
+    options.SetHasSourceSize(true);
+    options.SetBinaryZeroIsTerminator(false);
+    options.SetNeedsZeroTermination(false);
+    options.SetTrimTrailingZeros(true);
+  }
+
   if (!StringPrinter::ReadStringAndDumpToStream<ElemType>(options))
     stream.Printf("Summary Unavailable");
 
@@ -127,6 +137,16 @@ bool lldb_private::formatters::WCharStringSummaryProvider(
   options.SetStream(&stream);
   options.SetPrefixToken("L");
 
+  CompilerType ty = valobj.GetCompilerType();
+  uint64_t arr_size = 0;
+  if (ty.IsArrayType(nullptr, &arr_size) && arr_size > 0) {
+    options.SetSourceSize(arr_size);
+    options.SetHasSourceSize(true);
+    options.SetBinaryZeroIsTerminator(false);
+    options.SetNeedsZeroTermination(false);
+    options.SetTrimTrailingZeros(true);
+  }
+
   switch (wchar_size) {
   case 1:
     return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF8>(
diff --git a/lldb/test/API/lang/cpp/char1632_t/TestChar1632T.py b/lldb/test/API/lang/cpp/char1632_t/TestChar1632T.py
index e2521d88258bc..cd4dc9a406f5c 100644
--- a/lldb/test/API/lang/cpp/char1632_t/TestChar1632T.py
+++ b/lldb/test/API/lang/cpp/char1632_t/TestChar1632T.py
@@ -80,6 +80,12 @@ def test(self):
             substrs=['u"ﺸﺵۻ"', 'U"ЕЙРГЖО"'],
         )
 
+        # Check that embedded zeros show up in arrays
+        self.expect_var_path("aZero16", summary='u"I\\0have\\0zeros"')
+        self.expect_var_path("cZero16", summary='u"I"')
+        self.expect_var_path("aZero32", summary='U"I\\0have\\0zeros"')
+        self.expect_var_path("cZero32", summary='U"I"')
+
         self.runCmd("next")  # step to after the string is nullified
 
         # check that we don't crash on NULL
diff --git a/lldb/test/API/lang/cpp/char1632_t/main.cpp b/lldb/test/API/lang/cpp/char1632_t/main.cpp
index dc37df27fceb5..e38188cf85dee 100644
--- a/lldb/test/API/lang/cpp/char1632_t/main.cpp
+++ b/lldb/test/API/lang/cpp/char1632_t/main.cpp
@@ -10,7 +10,7 @@ void copy_char_seq (T (&arr)[N], const T* src)
     assert(src_len < N);
 
     std::char_traits<T>::copy(arr, src, src_len);
-    arr[src_len] = 0;
+    memset(&arr[src_len], 0, (N - src_len) * sizeof(T));
 }
 
 int main (int argc, char const *argv[])
@@ -25,6 +25,12 @@ int main (int argc, char const *argv[])
     char32_t *s32 = (char32_t *)U"ЕЙРГЖО";
     copy_char_seq(as16, s16);
     copy_char_seq(as32, s32);
+
+    char16_t aZero16[32] = u"I\0have\0zeros";
+    const char16_t *cZero16 = u"I\0have\0zeros";
+    char32_t aZero32[32] = U"I\0have\0zeros";
+    const char32_t *cZero32 = U"I\0have\0zeros";
+
     s32 = nullptr; // breakpoint1
     s32 = (char32_t *)U"෴";
     s16 = (char16_t *)u"色ハ匂ヘト散リヌルヲ";
diff --git a/lldb/test/API/lang/cpp/char8_t/TestCxxChar8_t.py b/lldb/test/API/lang/cpp/char8_t/TestCxxChar8_t.py
index 08f09b317b217..c727ae9cf6ab6 100644
--- a/lldb/test/API/lang/cpp/char8_t/TestCxxChar8_t.py
+++ b/lldb/test/API/lang/cpp/char8_t/TestCxxChar8_t.py
@@ -21,10 +21,18 @@ def test_without_process(self):
         self.expect("target variable a", substrs=["char8_t", "0x61 u8'a'"])
         self.expect("target variable ab", substrs=["const char8_t *", 'u8"你好"'])
         self.expect("target variable abc", substrs=["char8_t[9]", 'u8"你好"'])
+        self.expect(
+            "target variable aZero", substrs=["char8_t[32]", 'u8"I\\0have\\0zeros"']
+        )
+        self.expect("target variable cZero", substrs=["const char8_t *", 'u8"I"'])
 
         self.expect_expr("a", result_type="char8_t", result_summary="0x61 u8'a'")
         self.expect_expr("ab", result_type="const char8_t *", result_summary='u8"你好"')
         self.expect_expr("abc", result_type="char8_t[9]", result_summary='u8"你好"')
+        self.expect_expr(
+            "aZero", result_type="char8_t[32]", result_summary='u8"I\\0have\\0zeros"'
+        )
+        self.expect_expr("cZero", result_type="const char8_t *", result_summary='u8"I"')
 
     @skipIf(compiler="clang", compiler_version=["<", "7.0"])
     def test_with_process(self):
@@ -38,3 +46,7 @@ def test_with_process(self):
         self.expect_expr("a", result_type="char8_t", result_summary="0x61 u8'a'")
         self.expect_expr("ab", result_type="const char8_t *", result_summary='u8"你好"')
         self.expect_expr("abc", result_type="char8_t[9]", result_summary='u8"你好"')
+        self.expect_expr(
+            "aZero", result_type="char8_t[32]", result_summary='u8"I\\0have\\0zeros"'
+        )
+        self.expect_expr("cZero", result_type="const char8_t *", result_summary='u8"I"')
diff --git a/lldb/test/API/lang/cpp/char8_t/main.cpp b/lldb/test/API/lang/cpp/char8_t/main.cpp
index d109751cc2314..36a2bbef95e2b 100644
--- a/lldb/test/API/lang/cpp/char8_t/main.cpp
+++ b/lldb/test/API/lang/cpp/char8_t/main.cpp
@@ -2,6 +2,9 @@ char8_t a  = u8'a';
 const char8_t* ab = u8"你好";
 char8_t abc[9] = u8"你好";
 
+char8_t aZero[32] = u8"I\0have\0zeros";
+const char8_t *cZero = u8"I\0have\0zeros";
+
 int main (int argc, char const *argv[]) {
   return 0; // break here
 }
diff --git a/lldb/test/API/lang/cpp/wchar_t/TestCxxWCharT.py b/lldb/test/API/lang/cpp/wchar_t/TestCxxWCharT.py
index 35cb512142ca0..f17d5a707c9e3 100644
--- a/lldb/test/API/lang/cpp/wchar_t/TestCxxWCharT.py
+++ b/lldb/test/API/lang/cpp/wchar_t/TestCxxWCharT.py
@@ -48,3 +48,6 @@ def test(self):
 
         self.expect("frame variable wchar_zero", substrs=["L'\\0'"])
         self.expect("expression wchar_zero", substrs=["L'\\0'"])
+
+        self.expect_var_path("aZero", summary='L"I\\0have\\0zeros"')
+        self.expect_var_path("cZero", summary='L"I"')
diff --git a/lldb/test/API/lang/cpp/wchar_t/main.cpp b/lldb/test/API/lang/cpp/wchar_t/main.cpp
index 778642e0133f0..d479e2daf0697 100644
--- a/lldb/test/API/lang/cpp/wchar_t/main.cpp
+++ b/lldb/test/API/lang/cpp/wchar_t/main.cpp
@@ -19,8 +19,12 @@ int main (int argc, char const *argv[])
     const wchar_t *mazeltov = L"מזל טוב";
     wchar_t *ws_NULL = nullptr;
     wchar_t *ws_empty = L"";
-  	wchar_t array[200], * array_source = L"Hey, I'm a super wchar_t string, éõñž";
+    wchar_t array[200], * array_source = L"Hey, I'm a super wchar_t string, éõñž";
     wchar_t wchar_zero = (wchar_t)0;
-  	memcpy(array, array_source, 39 * sizeof(wchar_t));
+    memcpy(array, array_source, 39 * sizeof(wchar_t));
+
+    wchar_t aZero[32] = L"I\0have\0zeros";
+    const wchar_t *cZero = L"I\0have\0zeros";
+
     return 0; // break here
 }



More information about the lldb-commits mailing list