Skip to content

Commit 419fa1b

Browse files
authored
[lldb][DataFormatter] Surface CalculateNumChildren errors in std::vector summary (llvm#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
1 parent 0045b82 commit 419fa1b

File tree

5 files changed

+104
-8
lines changed

5 files changed

+104
-8
lines changed

lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp

+16-5
Original file line numberDiff line numberDiff line change
@@ -83,19 +83,30 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
8383
llvm::Expected<uint32_t> lldb_private::formatters::
8484
LibcxxStdVectorSyntheticFrontEnd::CalculateNumChildren() {
8585
if (!m_start || !m_finish)
86-
return 0;
86+
return llvm::createStringError(
87+
"Failed to determine start/end of vector data.");
88+
8789
uint64_t start_val = m_start->GetValueAsUnsigned(0);
8890
uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
8991

90-
if (start_val == 0 || finish_val == 0)
92+
// A default-initialized empty vector.
93+
if (start_val == 0 && finish_val == 0)
9194
return 0;
9295

93-
if (start_val >= finish_val)
94-
return 0;
96+
if (start_val == 0)
97+
return llvm::createStringError("Invalid value for start of vector.");
98+
99+
if (finish_val == 0)
100+
return llvm::createStringError("Invalid value for end of vector.");
101+
102+
if (start_val > finish_val)
103+
return llvm::createStringError(
104+
"Start of vector data begins after end pointer.");
95105

96106
size_t num_children = (finish_val - start_val);
97107
if (num_children % m_element_size)
98-
return 0;
108+
return llvm::createStringError("Size not multiple of element size.");
109+
99110
return num_children / m_element_size;
100111
}
101112

lldb/source/ValueObject/ValueObject.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -1521,10 +1521,16 @@ bool ValueObject::DumpPrintableRepresentation(
15211521
str = GetLocationAsCString();
15221522
break;
15231523

1524-
case eValueObjectRepresentationStyleChildrenCount:
1525-
strm.Printf("%" PRIu64 "", (uint64_t)GetNumChildrenIgnoringErrors());
1526-
str = strm.GetString();
1524+
case eValueObjectRepresentationStyleChildrenCount: {
1525+
if (auto err = GetNumChildren()) {
1526+
strm.Printf("%" PRIu32, *err);
1527+
str = strm.GetString();
1528+
} else {
1529+
strm << "error: " << toString(err.takeError());
1530+
str = strm.GetString();
1531+
}
15271532
break;
1533+
}
15281534

15291535
case eValueObjectRepresentationStyleType:
15301536
str = GetTypeName().GetStringRef();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CXX_SOURCES := main.cpp
2+
override CXXFLAGS_EXTRAS += -std=c++14
3+
include Makefile.rules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""
2+
Test we can understand various layouts of the libc++'s std::string
3+
"""
4+
5+
6+
import lldb
7+
from lldbsuite.test.decorators import *
8+
from lldbsuite.test.lldbtest import *
9+
from lldbsuite.test import lldbutil
10+
import functools
11+
12+
13+
class LibcxxInvalidVectorDataFormatterSimulatorTestCase(TestBase):
14+
NO_DEBUG_INFO_TESTCASE = True
15+
16+
def test(self):
17+
self.build()
18+
lldbutil.run_to_source_breakpoint(self, "return 0", lldb.SBFileSpec("main.cpp"))
19+
20+
self.expect(
21+
"frame variable v1",
22+
substrs=["size=error: Invalid value for end of vector."],
23+
)
24+
self.expect(
25+
"frame variable v2",
26+
substrs=["size=error: Invalid value for start of vector."],
27+
)
28+
self.expect(
29+
"frame variable v3",
30+
substrs=["size=error: Start of vector data begins after end pointer."],
31+
)
32+
self.expect(
33+
"frame variable v4",
34+
substrs=["size=error: Failed to determine start/end of vector data."],
35+
)
36+
self.expect(
37+
"frame variable v5",
38+
substrs=["size=error: Size not multiple of element size."],
39+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#define COMPRESSED_PAIR_REV 2
2+
#include <libcxx-simulators-common/compressed_pair.h>
3+
4+
namespace std {
5+
namespace __1 {
6+
template <typename T> struct vector {
7+
T *__begin_;
8+
T *__end_;
9+
_LLDB_COMPRESSED_PAIR(T *, __cap_ = nullptr, void *, __alloc_);
10+
};
11+
} // namespace __1
12+
13+
namespace __2 {
14+
template <typename T> struct vector {};
15+
} // namespace __2
16+
17+
namespace __3 {
18+
template <typename T> struct vector {
19+
T *__begin_;
20+
T *__end_;
21+
_LLDB_COMPRESSED_PAIR(short *, __cap_ = nullptr, void *, __alloc_);
22+
};
23+
} // namespace __3
24+
} // namespace std
25+
26+
int main() {
27+
int arr[] = {1, 2, 3};
28+
std::__1::vector<int> v1{.__begin_ = arr, .__end_ = nullptr};
29+
std::__1::vector<int> v2{.__begin_ = nullptr, .__end_ = arr};
30+
std::__1::vector<int> v3{.__begin_ = &arr[2], .__end_ = arr};
31+
std::__2::vector<int> v4;
32+
33+
char carr[] = {'a'};
34+
std::__3::vector<char> v5{.__begin_ = carr, .__end_ = carr + 1};
35+
36+
return 0;
37+
}

0 commit comments

Comments
 (0)