[Lldb-commits] [lldb] 419fa1b - [lldb][DataFormatter] Surface CalculateNumChildren errors in std::vector summary (#135944)

via lldb-commits lldb-commits at lists.llvm.org
Wed Apr 16 08:57:54 PDT 2025


Author: Michael Buch
Date: 2025-04-16T17:57:51+02:00
New Revision: 419fa1b06a36336ad85f1c71fc72ffa719ceb659

URL: https://github.com/llvm/llvm-project/commit/419fa1b06a36336ad85f1c71fc72ffa719ceb659
DIFF: https://github.com/llvm/llvm-project/commit/419fa1b06a36336ad85f1c71fc72ffa719ceb659.diff

LOG: [lldb][DataFormatter] Surface CalculateNumChildren errors in std::vector summary (#135944)

When the data-formatters happen to break (e.g., due to layout changes in
libc++), there's no clear indicator of them failing from a user's
perspective. E.g., for `std::vector`s we would just show:
```
(std::vector<int>) v = size=0 {}
```
which is highly misleading, especially if `v.size()` returns a non-zero
size.

This patch surfaces the various errors that could occur when calculating
the number of children of a vector.

rdar://146964266

Added: 
    lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/Makefile
    lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/TestDataFormatterLibcxxInvalidVectorSimulator.py
    lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/main.cpp

Modified: 
    lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
    lldb/source/ValueObject/ValueObject.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
index d538cac9f9134..ce2261b6f03c3 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
@@ -83,19 +83,30 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
 llvm::Expected<uint32_t> lldb_private::formatters::
     LibcxxStdVectorSyntheticFrontEnd::CalculateNumChildren() {
   if (!m_start || !m_finish)
-    return 0;
+    return llvm::createStringError(
+        "Failed to determine start/end of vector data.");
+
   uint64_t start_val = m_start->GetValueAsUnsigned(0);
   uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
 
-  if (start_val == 0 || finish_val == 0)
+  // A default-initialized empty vector.
+  if (start_val == 0 && finish_val == 0)
     return 0;
 
-  if (start_val >= finish_val)
-    return 0;
+  if (start_val == 0)
+    return llvm::createStringError("Invalid value for start of vector.");
+
+  if (finish_val == 0)
+    return llvm::createStringError("Invalid value for end of vector.");
+
+  if (start_val > finish_val)
+    return llvm::createStringError(
+        "Start of vector data begins after end pointer.");
 
   size_t num_children = (finish_val - start_val);
   if (num_children % m_element_size)
-    return 0;
+    return llvm::createStringError("Size not multiple of element size.");
+
   return num_children / m_element_size;
 }
 

diff  --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp
index eac24353de90b..8741cb7343166 100644
--- a/lldb/source/ValueObject/ValueObject.cpp
+++ b/lldb/source/ValueObject/ValueObject.cpp
@@ -1521,10 +1521,16 @@ bool ValueObject::DumpPrintableRepresentation(
       str = GetLocationAsCString();
       break;
 
-    case eValueObjectRepresentationStyleChildrenCount:
-      strm.Printf("%" PRIu64 "", (uint64_t)GetNumChildrenIgnoringErrors());
-      str = strm.GetString();
+    case eValueObjectRepresentationStyleChildrenCount: {
+      if (auto err = GetNumChildren()) {
+        strm.Printf("%" PRIu32, *err);
+        str = strm.GetString();
+      } else {
+        strm << "error: " << toString(err.takeError());
+        str = strm.GetString();
+      }
       break;
+    }
 
     case eValueObjectRepresentationStyleType:
       str = GetTypeName().GetStringRef();

diff  --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/Makefile
new file mode 100644
index 0000000000000..38cfa81053488
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+override CXXFLAGS_EXTRAS += -std=c++14
+include Makefile.rules

diff  --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/TestDataFormatterLibcxxInvalidVectorSimulator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/TestDataFormatterLibcxxInvalidVectorSimulator.py
new file mode 100644
index 0000000000000..8788ea7be882d
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/TestDataFormatterLibcxxInvalidVectorSimulator.py
@@ -0,0 +1,39 @@
+"""
+Test we can understand various layouts of the libc++'s std::string
+"""
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+import functools
+
+
+class LibcxxInvalidVectorDataFormatterSimulatorTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def test(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(self, "return 0", lldb.SBFileSpec("main.cpp"))
+
+        self.expect(
+            "frame variable v1",
+            substrs=["size=error: Invalid value for end of vector."],
+        )
+        self.expect(
+            "frame variable v2",
+            substrs=["size=error: Invalid value for start of vector."],
+        )
+        self.expect(
+            "frame variable v3",
+            substrs=["size=error: Start of vector data begins after end pointer."],
+        )
+        self.expect(
+            "frame variable v4",
+            substrs=["size=error: Failed to determine start/end of vector data."],
+        )
+        self.expect(
+            "frame variable v5",
+            substrs=["size=error: Size not multiple of element size."],
+        )

diff  --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/main.cpp
new file mode 100644
index 0000000000000..c9f04f60ec24d
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/main.cpp
@@ -0,0 +1,37 @@
+#define COMPRESSED_PAIR_REV 2
+#include <libcxx-simulators-common/compressed_pair.h>
+
+namespace std {
+namespace __1 {
+template <typename T> struct vector {
+  T *__begin_;
+  T *__end_;
+  _LLDB_COMPRESSED_PAIR(T *, __cap_ = nullptr, void *, __alloc_);
+};
+} // namespace __1
+
+namespace __2 {
+template <typename T> struct vector {};
+} // namespace __2
+
+namespace __3 {
+template <typename T> struct vector {
+  T *__begin_;
+  T *__end_;
+  _LLDB_COMPRESSED_PAIR(short *, __cap_ = nullptr, void *, __alloc_);
+};
+} // namespace __3
+} // namespace std
+
+int main() {
+  int arr[] = {1, 2, 3};
+  std::__1::vector<int> v1{.__begin_ = arr, .__end_ = nullptr};
+  std::__1::vector<int> v2{.__begin_ = nullptr, .__end_ = arr};
+  std::__1::vector<int> v3{.__begin_ = &arr[2], .__end_ = arr};
+  std::__2::vector<int> v4;
+
+  char carr[] = {'a'};
+  std::__3::vector<char> v5{.__begin_ = carr, .__end_ = carr + 1};
+
+  return 0;
+}


        


More information about the lldb-commits mailing list