Skip to content

Commit cd17cdc

Browse files
committed
[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 (cherry picked from commit 419fa1b)
1 parent f4418fb commit cd17cdc

File tree

5 files changed

+104
-8
lines changed

5 files changed

+104
-8
lines changed

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

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,30 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
8787
llvm::Expected<uint32_t> lldb_private::formatters::
8888
LibcxxStdVectorSyntheticFrontEnd::CalculateNumChildren() {
8989
if (!m_start || !m_finish)
90-
return 0;
90+
return llvm::createStringError(
91+
"Failed to determine start/end of vector data.");
92+
9193
uint64_t start_val = m_start->GetValueAsUnsigned(0);
9294
uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
9395

94-
if (start_val == 0 || finish_val == 0)
96+
// A default-initialized empty vector.
97+
if (start_val == 0 && finish_val == 0)
9598
return 0;
9699

97-
if (start_val >= finish_val)
98-
return 0;
100+
if (start_val == 0)
101+
return llvm::createStringError("Invalid value for start of vector.");
102+
103+
if (finish_val == 0)
104+
return llvm::createStringError("Invalid value for end of vector.");
105+
106+
if (start_val > finish_val)
107+
return llvm::createStringError(
108+
"Start of vector data begins after end pointer.");
99109

100110
size_t num_children = (finish_val - start_val);
101111
if (num_children % m_element_size)
102-
return 0;
112+
return llvm::createStringError("Size not multiple of element size.");
113+
103114
return num_children / m_element_size;
104115
}
105116

lldb/source/ValueObject/ValueObject.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,10 +1589,16 @@ bool ValueObject::DumpPrintableRepresentation(
15891589
str = GetLocationAsCString();
15901590
break;
15911591

1592-
case eValueObjectRepresentationStyleChildrenCount:
1593-
strm.Printf("%" PRIu64 "", (uint64_t)GetNumChildrenIgnoringErrors());
1594-
str = strm.GetString();
1592+
case eValueObjectRepresentationStyleChildrenCount: {
1593+
if (auto err = GetNumChildren()) {
1594+
strm.Printf("%" PRIu32, *err);
1595+
str = strm.GetString();
1596+
} else {
1597+
strm << "error: " << toString(err.takeError());
1598+
str = strm.GetString();
1599+
}
15951600
break;
1601+
}
15961602

15971603
case eValueObjectRepresentationStyleType:
15981604
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)