[Lldb-commits] [lldb] Teach LLDB's pretty-printer about libc++'s various `std::vector` layouts (PR #202438)
Christopher Di Bella via lldb-commits
lldb-commits at lists.llvm.org
Thu Jun 11 13:46:39 PDT 2026
https://github.com/cjdb updated https://github.com/llvm/llvm-project/pull/202438
>From 1e0ea28e5101ac228c3cead2d047e795faea3eb0 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Fri, 5 Jun 2026 22:49:49 +0000
Subject: [PATCH 1/8] Teach LLDB's pretty-printer about libc++'s various
`std::vector` layouts
PR #155330 changes `std::vector` from unconditionally using three
pointers to represent its layout to potentially using three pointers or
a begin pointer and two integers. This commit changes LLDB so that it
can robustly work with the legacy vector layout, the new pointer layout,
and the new size-based layout.
---
.../Language/CPlusPlus/LibCxxVector.cpp | 60 +++---
...taFormatterLibcxxInvalidVectorSimulator.py | 76 +++++++
.../libcxx-simulators/invalid-vector/main.cpp | 190 ++++++++++++++++--
.../libcxx-simulators/vector/Makefile | 3 +
.../TestDataFormatterLibcxxVectorSimulator.py | 44 ++++
.../libcxx-simulators/vector/main.cpp | 78 +++++++
6 files changed, 413 insertions(+), 38 deletions(-)
create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/Makefile
create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/TestDataFormatterLibcxxVectorSimulator.py
create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
index 95d12e8ee4f06..bf9010a304197 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
@@ -37,6 +37,8 @@ class LibcxxStdVectorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
private:
+ lldb::ChildCacheState UpdateVectorWithLayoutSubobject(ValueObject *layout);
+
ValueObject *m_start = nullptr;
ValueObject *m_finish = nullptr;
CompilerType m_element_type;
@@ -126,40 +128,50 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex(
m_element_type);
}
-static ValueObjectSP GetDataPointer(ValueObject &root) {
- auto [cap_sp, is_compressed_pair] =
- GetValueOrOldCompressedPair(root, "__cap_", "__end_cap_");
- if (!cap_sp)
- return nullptr;
-
- if (is_compressed_pair)
- return GetFirstValueOfLibCXXCompressedPair(*cap_sp);
-
- return cap_sp;
-}
-
lldb::ChildCacheState
lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() {
m_start = m_finish = nullptr;
- ValueObjectSP data_sp(GetDataPointer(m_backend));
- if (!data_sp)
+ // Determine if this version of libc++'s `std::vector` uses `__vector_layout`.
+ ValueObjectSP layout_sp = m_backend.GetChildMemberWithName("__layout_");
+ ValueObject *target = layout_sp ? layout_sp.get() : &m_backend;
+
+ ValueObjectSP begin_sp = target->GetChildMemberWithName("__begin_");
+ if (!begin_sp)
return lldb::ChildCacheState::eRefetch;
- m_element_type = data_sp->GetCompilerType().GetPointeeType();
+ m_element_type = begin_sp->GetCompilerType().GetPointeeType();
llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);
- if (!size_or_err)
+ if (!size_or_err) {
LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),
"{0}");
- else {
- m_element_size = *size_or_err;
-
- if (m_element_size > 0) {
- // store raw pointers or end up with a circular dependency
- m_start = m_backend.GetChildMemberWithName("__begin_").get();
- m_finish = m_backend.GetChildMemberWithName("__end_").get();
- }
+ return lldb::ChildCacheState::eRefetch;
+ }
+
+ m_element_size = *size_or_err;
+ if (m_element_size == 0) {
+ return lldb::ChildCacheState::eRefetch;
}
+
+ // store raw pointers or end up with a circular dependency
+ m_start = begin_sp.get();
+
+ if (ValueObjectSP end_sp = target->GetChildMemberWithName("__end_")) {
+ m_finish = end_sp.get();
+ return lldb::ChildCacheState::eRefetch;
+ }
+
+ ValueObjectSP size_sp = target->GetChildMemberWithName("__size_");
+ if (!size_sp || !size_sp->GetCompilerType().IsInteger())
+ return lldb::ChildCacheState::eRefetch;
+
+ uint64_t begin_addr = m_start->GetValueAsUnsigned(0);
+ uint64_t size = size_sp->GetValueAsUnsigned(0);
+ uint64_t end_addr = begin_addr + size * m_element_size;
+ m_finish = CreateChildValueObjectFromAddress(
+ "__end_", end_addr, m_backend.GetExecutionContextRef(),
+ m_start->GetCompilerType(), false)
+ .get();
return lldb::ChildCacheState::eRefetch;
}
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
index c3d51a49c3f5b..e4783746b3499 100644
--- 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
@@ -37,5 +37,81 @@ def test(self):
)
self.expect(
"frame variable v5",
+ substrs=["size=error: failed to determine start/end of vector data"],
+ )
+ self.expect(
+ "frame variable v6",
+ substrs=["size=error: failed to determine start/end of vector data"],
+ )
+ self.expect(
+ "frame variable v7",
+ substrs=["size=error: invalid value for end of vector"],
+ )
+ self.expect(
+ "frame variable v8",
+ substrs=["size=error: failed to determine start/end of vector data"],
+ )
+ self.expect(
+ "frame variable v9",
+ substrs=["size=error: failed to determine start/end of vector data"],
+ )
+ self.expect(
+ "frame variable v10",
+ substrs=["size=error: invalid value for end of vector"],
+ )
+ self.expect(
+ "frame variable v11",
+ substrs=["size=error: invalid value for start of vector"],
+ )
+ self.expect(
+ "frame variable v12",
+ substrs=["size=error: start of vector data begins after end pointer"],
+ )
+ self.expect(
+ "frame variable v13",
+ substrs=["size=error: failed to determine start/end of vector data"],
+ )
+ self.expect(
+ "frame variable v14",
+ substrs=["size=error: invalid value for end of vector"],
+ )
+ self.expect(
+ "frame variable v15",
+ substrs=["size=1"],
+ )
+ self.expect(
+ "frame variable v16",
+ substrs=["size=error: failed to determine start/end of vector data"],
+ )
+ self.expect(
+ "frame variable v17",
+ substrs=["size=error: failed to determine start/end of vector data"],
+ )
+ self.expect(
+ "frame variable v18",
+ substrs=["size=error: failed to determine start/end of vector data"],
+ )
+ self.expect(
+ "frame variable v19",
substrs=["size=error: size not multiple of element size"],
)
+ self.expect(
+ "frame variable v20",
+ substrs=["size=error: size not multiple of element size"],
+ )
+ self.expect(
+ "frame variable v21",
+ substrs=["size=1"],
+ )
+ self.expect(
+ "frame variable v23",
+ substrs=["size=error: failed to determine start/end of vector data"],
+ )
+ self.expect(
+ "frame variable v24",
+ substrs=["size=error: failed to determine start/end of vector data"],
+ )
+ self.expect(
+ "frame variable v25",
+ substrs=["size=error: failed to determine start/end of vector data"],
+ )
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
index 5943b35deab8b..f7a7e13356557 100644
--- 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
@@ -1,37 +1,199 @@
#define COMPRESSED_PAIR_REV 4
#include <libcxx-simulators-common/compressed_pair.h>
+#include <stddef.h>
namespace std {
-inline namespace __1 {
+inline namespace __ValidLegacyVector {
template <typename T> struct vector {
T *__begin_;
T *__end_;
- _LLDB_COMPRESSED_PAIR(T *, __cap_ = nullptr, void *, __alloc_);
};
-} // namespace __1
+} // namespace __ValidLegacyVector
-inline namespace __2 {
-template <typename T> struct vector {};
-} // namespace __2
+inline namespace __LegacyVectorMissingBegin {
+template <typename T> struct vector {
+ T *__end_;
+};
+} // namespace __LegacyVectorMissingBegin
-inline namespace __3 {
+inline namespace __LegacyVectorNonPointerBegin {
template <typename T> struct vector {
+ int __begin_;
+ T *__end_;
+};
+} // namespace __LegacyVectorNonPointerBegin
+
+inline namespace __LegacyMissingEnd {
+template <typename T> struct vector {
+ T *__begin_;
+};
+} // namespace __LegacyMissingEnd
+
+inline namespace __LegacyVectorNonPointerEnd {
+template <typename T> struct vector {
+ T *__begin_;
+ size_t __end_;
+};
+} // namespace __LegacyVectorNonPointerEnd
+
+inline namespace __LegacyVectorSizeBased {
+template <typename T> struct vector {
+ T *__begin_;
+ size_t __end_;
+};
+} // namespace __LegacyVectorSizeBased
+
+inline namespace __ValidPointerLayout {
+template <typename T> struct __vector_layout {
T *__begin_;
T *__end_;
- _LLDB_COMPRESSED_PAIR(short *, __cap_ = nullptr, void *, __alloc_);
};
-} // namespace __3
+
+template <typename T> struct vector {
+ __vector_layout<T> __layout_;
+};
+} // namespace __ValidPointerLayout
+
+inline namespace __PointerLayoutNonPointerBegin {
+template <typename T> struct __vector_layout {
+ size_t __begin_;
+ T *__end_;
+};
+
+template <typename T> struct vector {
+ __vector_layout<T> __layout_;
+};
+} // namespace __PointerLayoutNonPointerBegin
+
+inline namespace __PointerLayoutNonPointerEnd {
+template <typename T> struct __vector_layout {
+ T *__begin_;
+ size_t __end_;
+};
+
+template <typename T> struct vector {
+ __vector_layout<T> __layout_;
+};
+} // namespace __PointerLayoutNonPointerEnd
+
+inline namespace __LayoutStructMissingBegin {
+template <typename T> struct __vector_layout {
+ // LLDB short-circuits when it can't find `__begin_`, so other members aren't
+ // required for this type.
+};
+
+template <typename T> struct vector {
+ __vector_layout<T> __layout_;
+};
+} // namespace __LayoutStructMissingBegin
+
+inline namespace __LayoutStructMissingSecondMember {
+template <typename T> struct __vector_layout {
+ T *__begin_;
+};
+
+template <typename T> struct vector {
+ __vector_layout<T> __layout_;
+};
+} // namespace __LayoutStructMissingSecondMember
+
+inline namespace __ValidSizeLayout {
+template <typename T> struct __vector_layout {
+ T *__begin_;
+ size_t __size_;
+};
+template <typename T> struct vector {
+ __vector_layout<T> __layout_;
+};
+} // namespace __ValidSizeLayout
+
+inline namespace __SizeLayoutMissingBegin {
+template <typename T> struct __vector_layout {
+ size_t __size_;
+};
+template <typename T> struct vector {
+ __vector_layout<T> __layout_;
+};
+} // namespace __SizeLayoutMissingBegin
+
+inline namespace __SizeLayoutNonPointerBegin {
+template <typename T> struct __vector_layout {
+ size_t __begin_;
+ size_t __size_;
+};
+template <typename T> struct vector {
+ __vector_layout<T> __layout_;
+};
+} // namespace __SizeLayoutNonPointerBegin
+
+inline namespace __SizeLayoutNonIntegerSize {
+template <typename T> struct __vector_layout {
+ T *__begin_;
+ T *__size_;
+};
+template <typename T> struct vector {
+ __vector_layout<T> __layout_;
+};
+} // namespace __SizeLayoutNonIntegerSize
} // 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;
+ std::__ValidLegacyVector::vector<int> v1{.__begin_ = arr, .__end_ = nullptr};
+ std::__ValidLegacyVector::vector<int> v2{.__begin_ = nullptr, .__end_ = arr};
+ std::__ValidLegacyVector::vector<int> v3{.__begin_ = &arr[2], .__end_ = arr};
+ std::__LegacyVectorMissingBegin::vector<int> v4{.__end_ = arr};
+ std::__LegacyMissingEnd::vector<int> v5{.__begin_ = arr};
+ std::__LegacyVectorNonPointerBegin::vector<int> v6{.__begin_ = 0,
+ .__end_ = arr};
+ std::__LegacyVectorNonPointerEnd::vector<int> v7{.__begin_ = arr,
+ .__end_ = 0};
+
+ std::__LayoutStructMissingBegin::vector<int> v8{.__layout_ = {}};
+ std::__LayoutStructMissingSecondMember::vector<int> v9{
+ .__layout_ = {.__begin_ = arr}};
+
+ std::__ValidPointerLayout::vector<int> v10{
+ .__layout_ = {.__begin_ = arr, .__end_ = nullptr}};
+ std::__ValidPointerLayout::vector<int> v11{
+ .__layout_ = {.__begin_ = nullptr, .__end_ = arr}};
+ std::__ValidPointerLayout::vector<int> v12{
+ .__layout_ = {.__begin_ = &arr[2], .__end_ = arr}};
+
+ std::__PointerLayoutNonPointerBegin::vector<int> v13{
+ .__layout_ = {.__begin_ = 0, .__end_ = arr}};
+ std::__PointerLayoutNonPointerEnd::vector<int> v14{
+ .__layout_ = {.__begin_ = arr, .__end_ = 0}};
+
+ std::__ValidSizeLayout::vector<int> v15{
+ .__layout_ = {.__begin_ = arr, .__size_ = 1}};
+
+ std::__SizeLayoutMissingBegin::vector<int> v16{.__layout_ = {.__size_ = 1}};
+ std::__SizeLayoutNonPointerBegin::vector<int> v17{
+ .__layout_ = {.__begin_ = 0, .__size_ = 0}};
+ std::__SizeLayoutNonIntegerSize::vector<int> v18{
+ .__layout_ = {.__begin_ = arr, .__size_ = 0}};
char carr[] = {'a'};
- std::__3::vector<char> v5{.__begin_ = carr, .__end_ = carr + 1};
+ std::__ValidLegacyVector::vector<short> v19{
+ .__begin_ = reinterpret_cast<short *>(carr),
+ .__end_ = reinterpret_cast<short *>(carr + 1)};
+ std::__ValidPointerLayout::vector<short> v20{
+ .__layout_ = {.__begin_ = reinterpret_cast<short *>(carr),
+ .__end_ = reinterpret_cast<short *>(carr + 1)}};
+ std::__ValidSizeLayout::vector<short> v21{
+ .__layout_ = {.__begin_ = reinterpret_cast<short *>(carr), .__size_ = 1}};
+
+ struct ZeroSizeStruct {
+ int x[0];
+ };
+ static_assert(sizeof(ZeroSizeStruct) == 0);
+ std::__ValidLegacyVector::vector<ZeroSizeStruct> v23{.__begin_ = nullptr,
+ .__end_ = nullptr};
+ std::__ValidPointerLayout::vector<ZeroSizeStruct> v24{
+ .__layout_ = {.__begin_ = nullptr, .__end_ = nullptr}};
+ std::__ValidSizeLayout::vector<ZeroSizeStruct> v25{
+ .__layout_ = {.__begin_ = nullptr, .__size_ = 0}};
return 0;
}
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/Makefile
new file mode 100644
index 0000000000000..8ce653ffd6871
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+override CXXFLAGS_EXTRAS += -std=c++11
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/TestDataFormatterLibcxxVectorSimulator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/TestDataFormatterLibcxxVectorSimulator.py
new file mode 100644
index 0000000000000..46b22ad473191
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/TestDataFormatterLibcxxVectorSimulator.py
@@ -0,0 +1,44 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class LibcxxVectorDataFormatterSimulatorTestCase(TestBase):
+ SHARED_BUILD_TESTCASE = False
+ NO_DEBUG_INFO_TESTCASE = True
+ test_cases = {
+ "LLDB_TEST_VECTOR_WITHOUT_LAYOUT_DATA_MEMBER": 0,
+ "LLDB_TEST_VECTOR_WITH_POINTER_LAYOUT": 1,
+ "LLDB_TEST_VECTOR_WITH_SIZE_LAYOUT": 2,
+ }
+
+ def _run_test(self, test_case):
+ cxxflags_extras = f"-DLLDB_TEST_CASE={test_case}"
+ self.build(dictionary=dict(CXXFLAGS_EXTRAS=cxxflags_extras))
+ lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.cpp"))
+
+ self.expect(
+ "frame variable v0",
+ substrs=["size=0"],
+ )
+ self.expect(
+ "frame variable v1",
+ substrs=["size=1", "[0] = 10"],
+ )
+ self.expect(
+ "frame variable v2",
+ substrs=["size=2", "[0] = -10", "[1] = -20"],
+ )
+ self.expect(
+ "frame variable v3",
+ substrs=["size=3", "[0] = 56", "[1] = 10", "[2] = 87"],
+ )
+
+ def test_without_layout_member(self):
+ self._run_test(self.test_cases["LLDB_TEST_VECTOR_WITHOUT_LAYOUT_DATA_MEMBER"])
+
+ def test_with_pointer_layout(self):
+ self._run_test(self.test_cases["LLDB_TEST_VECTOR_WITH_POINTER_LAYOUT"])
+
+ def test_with_size_layout(self):
+ self._run_test(self.test_cases["LLDB_TEST_VECTOR_WITH_SIZE_LAYOUT"])
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp
new file mode 100644
index 0000000000000..9bfbddba63238
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp
@@ -0,0 +1,78 @@
+#include <stddef.h>
+
+#define LLDB_TEST_VECTOR_WITHOUT_LAYOUT_DATA_MEMBER 0
+#define LLDB_TEST_VECTOR_WITH_POINTER_LAYOUT 1
+#define LLDB_TEST_VECTOR_WITH_SIZE_LAYOUT 2
+#define LLDB_TEST_VECTOR_WITH_LAYOUT_MISSING_DATA_MEMBERS 3
+
+#ifndef LLDB_TEST_CASE
+#error LLDB_TEST_CASE must be defined as an integer
+#endif
+
+namespace std {
+namespace __lldb {
+
+#if LLDB_TEST_CASE == LLDB_TEST_VECTOR_WITHOUT_LAYOUT_DATA_MEMBER
+template <typename T> class vector {
+public:
+ typedef T *pointer;
+
+ vector(pointer begin, size_t size)
+ : __begin_(begin), __end_(begin + size) {}
+
+private:
+ pointer __begin_;
+ pointer __end_;
+ // __cap_ and __alloc_ aren't used, so they've been removed for simplicity.
+};
+#elif LLDB_TEST_CASE == LLDB_TEST_VECTOR_WITH_POINTER_LAYOUT
+template <typename T> struct __vector_layout {
+ T *__begin_;
+ T *__end_;
+};
+
+template <typename T> class vector {
+public:
+ vector(T *begin, size_t size) : __layout_{begin, begin + size} {}
+
+private:
+ __vector_layout<T> __layout_;
+};
+
+#elif LLDB_TEST_CASE == LLDB_TEST_VECTOR_WITH_SIZE_LAYOUT
+template <typename T> struct __vector_layout {
+ T *__begin_;
+ size_t __size_;
+};
+
+template <typename T> class vector {
+public:
+ vector(T *begin, size_t size) : __layout_{begin, size} {}
+
+private:
+ __vector_layout<T> __layout_;
+};
+
+#else
+#error LLDB_TEST_CASE defined out-of-range
+#undef LLDB_TEST_CASE
+#endif
+
+} // namespace __lldb
+} // namespace std
+
+int main() {
+#ifdef LLDB_TEST_CASE
+ int a1[] = {10};
+ std::__lldb::vector<int> v0(a1, 0);
+ std::__lldb::vector<int> v1(a1, 1);
+
+ int a2[] = {-10, -20};
+ std::__lldb::vector<int> v2(a2, 2);
+
+ int a3[] = {56, 10, 87};
+ std::__lldb::vector<int> v3(a3, 3);
+
+ return 0; // break here
+#endif
+}
>From f86c4a9b8ddc24de8e0801730917ffd86e464664 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Mon, 8 Jun 2026 21:45:36 +0000
Subject: [PATCH 2/8] Fix CI issues
---
.../TestDataFormatterLibcxxInvalidVectorSimulator.py | 10 ++++++++--
.../libcxx-simulators/invalid-vector/main.cpp | 2 ++
.../vector/TestDataFormatterLibcxxVectorSimulator.py | 4 +++-
3 files changed, 13 insertions(+), 3 deletions(-)
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
index e4783746b3499..0d21cc5717c20 100644
--- 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
@@ -13,9 +13,8 @@
class LibcxxInvalidVectorDataFormatterSimulatorTestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True
-
@skipIf(compiler="clang", compiler_version=['<', '18.0'])
- def test(self):
+ def test_most(self):
self.build()
lldbutil.run_to_source_breakpoint(self, "return 0", lldb.SBFileSpec("main.cpp"))
@@ -103,6 +102,13 @@ def test(self):
"frame variable v21",
substrs=["size=1"],
)
+
+ @skipIf(compiler="clang", compiler_version=["<", "18.0"])
+ @skipIfWindows
+ def test_zero_sized_struct_extension(self):
+ self.build()
+ lldbutil.run_to_source_breakpoint(self, "return 0", lldb.SBFileSpec("main.cpp"))
+
self.expect(
"frame variable v23",
substrs=["size=error: failed to determine start/end of vector data"],
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
index f7a7e13356557..cc4a3d4a771f8 100644
--- 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
@@ -184,6 +184,7 @@ int main() {
std::__ValidSizeLayout::vector<short> v21{
.__layout_ = {.__begin_ = reinterpret_cast<short *>(carr), .__size_ = 1}};
+#ifndef _WIN32
struct ZeroSizeStruct {
int x[0];
};
@@ -195,5 +196,6 @@ int main() {
.__layout_ = {.__begin_ = nullptr, .__end_ = nullptr}};
std::__ValidSizeLayout::vector<ZeroSizeStruct> v25{
.__layout_ = {.__begin_ = nullptr, .__size_ = 0}};
+#endif
return 0;
}
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/TestDataFormatterLibcxxVectorSimulator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/TestDataFormatterLibcxxVectorSimulator.py
index 46b22ad473191..9a480fb1b8d25 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/TestDataFormatterLibcxxVectorSimulator.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/TestDataFormatterLibcxxVectorSimulator.py
@@ -15,7 +15,9 @@ class LibcxxVectorDataFormatterSimulatorTestCase(TestBase):
def _run_test(self, test_case):
cxxflags_extras = f"-DLLDB_TEST_CASE={test_case}"
self.build(dictionary=dict(CXXFLAGS_EXTRAS=cxxflags_extras))
- lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.cpp"))
+ lldbutil.run_to_source_breakpoint(
+ self, "break here", lldb.SBFileSpec("main.cpp")
+ )
self.expect(
"frame variable v0",
>From 6eb35d03fe69e91f7bdc378ffbd6d26c375860be Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Mon, 8 Jun 2026 21:56:31 +0000
Subject: [PATCH 3/8] formats patch and updates test config
---
.../TestDataFormatterLibcxxVectorSimulator.py | 62 ++++++++++++-------
.../libcxx-simulators/vector/main.cpp | 47 +++++++-------
2 files changed, 64 insertions(+), 45 deletions(-)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/TestDataFormatterLibcxxVectorSimulator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/TestDataFormatterLibcxxVectorSimulator.py
index 9a480fb1b8d25..7d9aa8b829c0b 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/TestDataFormatterLibcxxVectorSimulator.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/TestDataFormatterLibcxxVectorSimulator.py
@@ -3,44 +3,62 @@
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
+
class LibcxxVectorDataFormatterSimulatorTestCase(TestBase):
SHARED_BUILD_TESTCASE = False
NO_DEBUG_INFO_TESTCASE = True
- test_cases = {
- "LLDB_TEST_VECTOR_WITHOUT_LAYOUT_DATA_MEMBER": 0,
- "LLDB_TEST_VECTOR_WITH_POINTER_LAYOUT": 1,
- "LLDB_TEST_VECTOR_WITH_SIZE_LAYOUT": 2,
- }
- def _run_test(self, test_case):
- cxxflags_extras = f"-DLLDB_TEST_CASE={test_case}"
- self.build(dictionary=dict(CXXFLAGS_EXTRAS=cxxflags_extras))
- lldbutil.run_to_source_breakpoint(
- self, "break here", lldb.SBFileSpec("main.cpp")
- )
+ def test(self):
+ self.build()
+ lldbutil.run_to_source_breakpoint(self, "return 0", lldb.SBFileSpec("main.cpp"))
self.expect(
- "frame variable v0",
+ "frame variable legacy_layout0",
substrs=["size=0"],
)
self.expect(
- "frame variable v1",
+ "frame variable legacy_layout1",
substrs=["size=1", "[0] = 10"],
)
self.expect(
- "frame variable v2",
+ "frame variable legacy_layout2",
substrs=["size=2", "[0] = -10", "[1] = -20"],
)
self.expect(
- "frame variable v3",
+ "frame variable legacy_layout3",
substrs=["size=3", "[0] = 56", "[1] = 10", "[2] = 87"],
)
- def test_without_layout_member(self):
- self._run_test(self.test_cases["LLDB_TEST_VECTOR_WITHOUT_LAYOUT_DATA_MEMBER"])
-
- def test_with_pointer_layout(self):
- self._run_test(self.test_cases["LLDB_TEST_VECTOR_WITH_POINTER_LAYOUT"])
+ self.expect(
+ "frame variable pointer_based_layout0",
+ substrs=["size=0"],
+ )
+ self.expect(
+ "frame variable pointer_based_layout1",
+ substrs=["size=1", "[0] = 10"],
+ )
+ self.expect(
+ "frame variable pointer_based_layout2",
+ substrs=["size=2", "[0] = -10", "[1] = -20"],
+ )
+ self.expect(
+ "frame variable pointer_based_layout3",
+ substrs=["size=3", "[0] = 56", "[1] = 10", "[2] = 87"],
+ )
- def test_with_size_layout(self):
- self._run_test(self.test_cases["LLDB_TEST_VECTOR_WITH_SIZE_LAYOUT"])
+ self.expect(
+ "frame variable size_based_layout0",
+ substrs=["size=0"],
+ )
+ self.expect(
+ "frame variable size_based_layout1",
+ substrs=["size=1", "[0] = 10"],
+ )
+ self.expect(
+ "frame variable size_based_layout2",
+ substrs=["size=2", "[0] = -10", "[1] = -20"],
+ )
+ self.expect(
+ "frame variable size_based_layout3",
+ substrs=["size=3", "[0] = 56", "[1] = 10", "[2] = 87"],
+ )
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp
index 9bfbddba63238..02cc67bc41112 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp
@@ -10,22 +10,21 @@
#endif
namespace std {
-namespace __lldb {
-
-#if LLDB_TEST_CASE == LLDB_TEST_VECTOR_WITHOUT_LAYOUT_DATA_MEMBER
+inline namespace __LegacyLayout {
template <typename T> class vector {
public:
typedef T *pointer;
- vector(pointer begin, size_t size)
- : __begin_(begin), __end_(begin + size) {}
+ vector(pointer begin, size_t size) : __begin_(begin), __end_(begin + size) {}
private:
pointer __begin_;
pointer __end_;
// __cap_ and __alloc_ aren't used, so they've been removed for simplicity.
};
-#elif LLDB_TEST_CASE == LLDB_TEST_VECTOR_WITH_POINTER_LAYOUT
+} // namespace __LegacyLayout
+
+inline namespace __PointerBasedLayout {
template <typename T> struct __vector_layout {
T *__begin_;
T *__end_;
@@ -38,8 +37,9 @@ template <typename T> class vector {
private:
__vector_layout<T> __layout_;
};
+} // namespace __PointerBasedLayout
-#elif LLDB_TEST_CASE == LLDB_TEST_VECTOR_WITH_SIZE_LAYOUT
+inline namespace __SizeBasedLayout {
template <typename T> struct __vector_layout {
T *__begin_;
size_t __size_;
@@ -52,27 +52,28 @@ template <typename T> class vector {
private:
__vector_layout<T> __layout_;
};
-
-#else
-#error LLDB_TEST_CASE defined out-of-range
-#undef LLDB_TEST_CASE
-#endif
-
-} // namespace __lldb
+} // namespace __SizeBasedLayout
} // namespace std
int main() {
-#ifdef LLDB_TEST_CASE
int a1[] = {10};
- std::__lldb::vector<int> v0(a1, 0);
- std::__lldb::vector<int> v1(a1, 1);
-
int a2[] = {-10, -20};
- std::__lldb::vector<int> v2(a2, 2);
-
int a3[] = {56, 10, 87};
- std::__lldb::vector<int> v3(a3, 3);
- return 0; // break here
-#endif
+ std::__LegacyLayout::vector<int> legacy_layout0(a1, 0);
+ std::__LegacyLayout::vector<int> legacy_layout1(a1, 1);
+ std::__LegacyLayout::vector<int> legacy_layout2(a2, 2);
+ std::__LegacyLayout::vector<int> legacy_layout3(a3, 3);
+
+ std::__PointerBasedLayout::vector<int> pointer_based_layout0(a1, 0);
+ std::__PointerBasedLayout::vector<int> pointer_based_layout1(a1, 1);
+ std::__PointerBasedLayout::vector<int> pointer_based_layout2(a2, 2);
+ std::__PointerBasedLayout::vector<int> pointer_based_layout3(a3, 3);
+
+ std::__SizeBasedLayout::vector<int> size_based_layout0(a1, 0);
+ std::__SizeBasedLayout::vector<int> size_based_layout1(a1, 1);
+ std::__SizeBasedLayout::vector<int> size_based_layout2(a2, 2);
+ std::__SizeBasedLayout::vector<int> size_based_layout3(a3, 3);
+
+ return 0;
}
>From 597a8e0b076c45279bfd009d3a92b04988adcb8c Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Mon, 8 Jun 2026 22:38:56 +0000
Subject: [PATCH 4/8] removes macros from previous implementation
---
.../data-formatter-stl/libcxx-simulators/vector/main.cpp | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp
index 02cc67bc41112..535faebac4157 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp
@@ -1,14 +1,5 @@
#include <stddef.h>
-#define LLDB_TEST_VECTOR_WITHOUT_LAYOUT_DATA_MEMBER 0
-#define LLDB_TEST_VECTOR_WITH_POINTER_LAYOUT 1
-#define LLDB_TEST_VECTOR_WITH_SIZE_LAYOUT 2
-#define LLDB_TEST_VECTOR_WITH_LAYOUT_MISSING_DATA_MEMBERS 3
-
-#ifndef LLDB_TEST_CASE
-#error LLDB_TEST_CASE must be defined as an integer
-#endif
-
namespace std {
inline namespace __LegacyLayout {
template <typename T> class vector {
>From a7c326ea06aaa5b6170a6b7ee40c823aee98a090 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Wed, 10 Jun 2026 00:51:13 +0000
Subject: [PATCH 5/8] change how we compute size
---
.../Language/CPlusPlus/LibCxxVector.cpp | 50 ++++++++++++-------
...taFormatterLibcxxInvalidVectorSimulator.py | 2 +-
2 files changed, 33 insertions(+), 19 deletions(-)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
index bf9010a304197..c11fdd5415982 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
@@ -13,6 +13,7 @@
#include "lldb/ValueObject/ValueObject.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-forward.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorExtras.h"
#include <optional>
@@ -41,6 +42,8 @@ class LibcxxStdVectorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
ValueObject *m_start = nullptr;
ValueObject *m_finish = nullptr;
+ enum class VectorLayout : bool { Pointer, Size };
+ VectorLayout m_layout;
CompilerType m_element_type;
uint32_t m_element_size = 0;
};
@@ -83,14 +86,9 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
// delete m_finish;
}
-llvm::Expected<uint32_t> lldb_private::formatters::
- LibcxxStdVectorSyntheticFrontEnd::CalculateNumChildren() {
- if (!m_start || !m_finish)
- 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);
+static llvm::Expected<uint32_t> CalculateNumChildrenUsingPointerArithmetic(ValueObject* begin, ValueObject* end, uint64_t value_type_size) {
+ uint64_t start_val = begin->GetValueAsUnsigned(0);
+ uint64_t finish_val = end->GetValueAsUnsigned(0);
// A default-initialized empty vector.
if (start_val == 0 && finish_val == 0)
@@ -107,10 +105,30 @@ llvm::Expected<uint32_t> lldb_private::formatters::
"start of vector data begins after end pointer");
size_t num_children = (finish_val - start_val);
- if (num_children % m_element_size)
+ if (num_children % value_type_size)
return llvm::createStringError("size not multiple of element size");
- return num_children / m_element_size;
+ return num_children / value_type_size;
+}
+
+static llvm::Expected<uint32_t> GetNumChildren(ValueObject* size) {
+ if (!size->GetCompilerType().IsInteger())
+ return llvm::createStringError("size data member must be a built-in integer type");
+ return size->GetValueAsUnsigned(0);
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ LibcxxStdVectorSyntheticFrontEnd::CalculateNumChildren() {
+ if (!m_start || !m_finish)
+ return llvm::createStringError(
+ "failed to determine start/end of vector data");
+
+ switch (m_layout) {
+ case VectorLayout::Pointer:
+ return CalculateNumChildrenUsingPointerArithmetic(m_start, m_finish, m_element_size);
+ case VectorLayout::Size:
+ return GetNumChildren(m_finish);
+ }
}
lldb::ValueObjectSP
@@ -158,20 +176,16 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() {
if (ValueObjectSP end_sp = target->GetChildMemberWithName("__end_")) {
m_finish = end_sp.get();
+ m_layout = VectorLayout::Pointer;
return lldb::ChildCacheState::eRefetch;
}
ValueObjectSP size_sp = target->GetChildMemberWithName("__size_");
- if (!size_sp || !size_sp->GetCompilerType().IsInteger())
+ if (!size_sp)
return lldb::ChildCacheState::eRefetch;
- uint64_t begin_addr = m_start->GetValueAsUnsigned(0);
- uint64_t size = size_sp->GetValueAsUnsigned(0);
- uint64_t end_addr = begin_addr + size * m_element_size;
- m_finish = CreateChildValueObjectFromAddress(
- "__end_", end_addr, m_backend.GetExecutionContextRef(),
- m_start->GetCompilerType(), false)
- .get();
+ m_finish = size_sp.get();
+ m_layout = VectorLayout::Size;
return lldb::ChildCacheState::eRefetch;
}
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
index 0d21cc5717c20..e79d0fe13de8c 100644
--- 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
@@ -88,7 +88,7 @@ def test_most(self):
)
self.expect(
"frame variable v18",
- substrs=["size=error: failed to determine start/end of vector data"],
+ substrs=["size=error: size data member must be a built-in integer type"],
)
self.expect(
"frame variable v19",
>From fc35d1b8dbcad3f4e428182b1176e492f38a43d7 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Wed, 10 Jun 2026 00:55:15 +0000
Subject: [PATCH 6/8] run clang-format
---
.../Language/CPlusPlus/LibCxxVector.cpp | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
index c11fdd5415982..7a455bd71ad8e 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
@@ -86,7 +86,9 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
// delete m_finish;
}
-static llvm::Expected<uint32_t> CalculateNumChildrenUsingPointerArithmetic(ValueObject* begin, ValueObject* end, uint64_t value_type_size) {
+static llvm::Expected<uint32_t>
+CalculateNumChildrenUsingPointerArithmetic(ValueObject *begin, ValueObject *end,
+ uint64_t value_type_size) {
uint64_t start_val = begin->GetValueAsUnsigned(0);
uint64_t finish_val = end->GetValueAsUnsigned(0);
@@ -111,9 +113,10 @@ static llvm::Expected<uint32_t> CalculateNumChildrenUsingPointerArithmetic(Value
return num_children / value_type_size;
}
-static llvm::Expected<uint32_t> GetNumChildren(ValueObject* size) {
+static llvm::Expected<uint32_t> GetNumChildren(ValueObject *size) {
if (!size->GetCompilerType().IsInteger())
- return llvm::createStringError("size data member must be a built-in integer type");
+ return llvm::createStringError(
+ "size data member must be a built-in integer type");
return size->GetValueAsUnsigned(0);
}
@@ -124,10 +127,11 @@ llvm::Expected<uint32_t> lldb_private::formatters::
"failed to determine start/end of vector data");
switch (m_layout) {
- case VectorLayout::Pointer:
- return CalculateNumChildrenUsingPointerArithmetic(m_start, m_finish, m_element_size);
- case VectorLayout::Size:
- return GetNumChildren(m_finish);
+ case VectorLayout::Pointer:
+ return CalculateNumChildrenUsingPointerArithmetic(m_start, m_finish,
+ m_element_size);
+ case VectorLayout::Size:
+ return GetNumChildren(m_finish);
}
}
>From 142ab729f05112d3e97fb8d2a04ca5940b07cbb8 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Thu, 11 Jun 2026 20:36:01 +0000
Subject: [PATCH 7/8] Document how vector is represented in libc++
---
.../libcxx-simulators/vector/main.cpp | 30 ++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp
index 535faebac4157..b46793ce5c9d7 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/vector/main.cpp
@@ -1,3 +1,17 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// libc++ has changed how `std::vector` is represented over time. This file
+// provides approximations of these representations for testing the vector
+// pretty-printer. This lets us test that LLDB is able to handle all iterations
+// of libc++'s `std::vector`.
+
#include <stddef.h>
namespace std {
@@ -11,11 +25,25 @@ template <typename T> class vector {
private:
pointer __begin_;
pointer __end_;
- // __cap_ and __alloc_ aren't used, so they've been removed for simplicity.
+
+ // libc++ changed how the capacity member and allocator were stored in
+ // 27c8338. LLDB only relies on `__begin_` and `__end_`. Adding the capacity
+ // and allocator members in their different formats doesn't add test coverage,
+ // but may convince the reader that it does. As such, we don't provide two
+ // legacy layouts.
+ //
+ // Before 27c83382d83dce0f33ae67abb3bc94977cb3031f:
+ // __compressed_pair<size_type, __storage_allocator> __cap_alloc_;
+ //
+ // Since 27c83382d83dce0f33ae67abb3bc94977cb3031f:
+ // _LIBCPP_COMPRESSED_PAIR(pointer, __cap_ = nullptr, allocator_type,
+ // __alloc_);
};
} // namespace __LegacyLayout
inline namespace __PointerBasedLayout {
+// `__PointerBasedLayout::__vector_layout` is structurally equal to
+// `__LegacyLayout::vector`.
template <typename T> struct __vector_layout {
T *__begin_;
T *__end_;
>From dd341a55d31950732b27350375ebdc7674a45301 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Thu, 11 Jun 2026 20:46:01 +0000
Subject: [PATCH 8/8] Document what `m_finish` can point to
---
lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
index 7a455bd71ad8e..4966eb1d75b20 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
@@ -41,6 +41,10 @@ class LibcxxStdVectorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
lldb::ChildCacheState UpdateVectorWithLayoutSubobject(ValueObject *layout);
ValueObject *m_start = nullptr;
+
+ // m_finish may point to a pointer (`__end_`) or an integer (`__size_`)
+ // depending on how libc++'s vector is implemented. Interpreting what is
+ // pointed to is done using `m_layout`.
ValueObject *m_finish = nullptr;
enum class VectorLayout : bool { Pointer, Size };
VectorLayout m_layout;
More information about the lldb-commits
mailing list