[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:33:21 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: Nerixyz (Nerixyz)
<details>
<summary>Changes</summary>
When formatting `char[N]` (N > 0), the read buffer is limited to the array size and trailing zeros are trimmed.
`charN_t[N]` was treated like a `charN_t *` and the formatter read until the first zero byte.
If the array doesn't have any zero bytes in it, this will read too much. If the array has zero bytes in it, it will show too little.
With this PR, `wchar_t[N]` and `charN_t[N]` are printed like `char[N]`.
---
Full diff: https://github.com/llvm/llvm-project/pull/195514.diff
9 Files Affected:
- (modified) lldb/include/lldb/DataFormatters/StringPrinter.h (+7)
- (modified) lldb/source/DataFormatters/StringPrinter.cpp (+12)
- (modified) lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp (+20)
- (modified) lldb/test/API/lang/cpp/char1632_t/TestChar1632T.py (+6)
- (modified) lldb/test/API/lang/cpp/char1632_t/main.cpp (+7-1)
- (modified) lldb/test/API/lang/cpp/char8_t/TestCxxChar8_t.py (+12)
- (modified) lldb/test/API/lang/cpp/char8_t/main.cpp (+3)
- (modified) lldb/test/API/lang/cpp/wchar_t/TestCxxWCharT.py (+3)
- (modified) lldb/test/API/lang/cpp/wchar_t/main.cpp (+7-2)
``````````diff
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..f6031ae9f7b9d 100644
--- a/lldb/test/API/lang/cpp/wchar_t/main.cpp
+++ b/lldb/test/API/lang/cpp/wchar_t/main.cpp
@@ -19,8 +19,13 @@ 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
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/195514
More information about the lldb-commits
mailing list