Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
12 changes: 9 additions & 3 deletions lldb/source/ValueObject/ValueObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp
override CXXFLAGS_EXTRAS += -std=c++14
include Makefile.rules
Original file line number Diff line number Diff line change
@@ -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."],
)
Original file line number Diff line number Diff line change
@@ -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;
}
Loading