diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -468,22 +468,20 @@ eLibcxxStringLayoutModeInvalid = 0xffff }; -// this function abstracts away the layout and mode details of a libc++ string -// and returns the address of the data and the size ready for callers to -// consume -static bool ExtractLibcxxStringInfo(ValueObject &valobj, - ValueObjectSP &location_sp, - uint64_t &size) { +/// Determine the size in bytes of \p valobj (a libc++ std::string object) and +/// extract its data payload. Return the size + payload pair. +static llvm::Optional> +ExtractLibcxxStringInfo(ValueObject &valobj) { ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0})); if (!D) - return false; + return {}; ValueObjectSP layout_decider( D->GetChildAtIndexPath(llvm::ArrayRef({0, 0}))); // this child should exist if (!layout_decider) - return false; + return {}; ConstString g_data_name("__data_"); ConstString g_size_name("__size_"); @@ -497,13 +495,13 @@ if (layout == eLibcxxStringLayoutModeDSC) { ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 1, 0})); if (!size_mode) - return false; + return {}; if (size_mode->GetName() != g_size_name) { // we are hitting the padding structure, move along size_mode = D->GetChildAtIndexPath({1, 1, 1}); if (!size_mode) - return false; + return {}; } size_mode_value = (size_mode->GetValueAsUnsigned(0)); @@ -511,7 +509,7 @@ } else { ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 0, 0})); if (!size_mode) - return false; + return {}; size_mode_value = (size_mode->GetValueAsUnsigned(0)); short_mode = ((size_mode_value & 1) == 0); @@ -520,12 +518,12 @@ if (short_mode) { ValueObjectSP s(D->GetChildAtIndex(1, true)); if (!s) - return false; - location_sp = s->GetChildAtIndex( + return {}; + ValueObjectSP location_sp = s->GetChildAtIndex( (layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true); - size = (layout == eLibcxxStringLayoutModeDSC) - ? size_mode_value - : ((size_mode_value >> 1) % 256); + const uint64_t size = (layout == eLibcxxStringLayoutModeDSC) + ? size_mode_value + : ((size_mode_value >> 1) % 256); // When the small-string optimization takes place, the data must fit in the // inline string buffer (23 bytes on x86_64/Darwin). If it doesn't, it's @@ -534,39 +532,44 @@ const llvm::Optional max_bytes = location_sp->GetCompilerType().GetByteSize( exe_ctx.GetBestExecutionContextScope()); - if (!max_bytes || size > *max_bytes) - return false; + if (!max_bytes || size > *max_bytes || !location_sp) + return {}; - return (location_sp.get() != nullptr); - } else { - ValueObjectSP l(D->GetChildAtIndex(0, true)); - if (!l) - return false; - // we can use the layout_decider object as the data pointer - location_sp = (layout == eLibcxxStringLayoutModeDSC) - ? layout_decider - : l->GetChildAtIndex(2, true); - ValueObjectSP size_vo(l->GetChildAtIndex(1, true)); - const unsigned capacity_index = - (layout == eLibcxxStringLayoutModeDSC) ? 2 : 0; - ValueObjectSP capacity_vo(l->GetChildAtIndex(capacity_index, true)); - if (!size_vo || !location_sp || !capacity_vo) - return false; - size = size_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET); - const uint64_t cap = capacity_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET); - if (size == LLDB_INVALID_OFFSET || cap == LLDB_INVALID_OFFSET || cap < size) - return false; - return true; + return std::make_pair(size, location_sp); } + + ValueObjectSP l(D->GetChildAtIndex(0, true)); + if (!l) + return {}; + // we can use the layout_decider object as the data pointer + ValueObjectSP location_sp = (layout == eLibcxxStringLayoutModeDSC) + ? layout_decider + : l->GetChildAtIndex(2, true); + ValueObjectSP size_vo(l->GetChildAtIndex(1, true)); + const unsigned capacity_index = + (layout == eLibcxxStringLayoutModeDSC) ? 2 : 0; + ValueObjectSP capacity_vo(l->GetChildAtIndex(capacity_index, true)); + if (!size_vo || !location_sp || !capacity_vo) + return {}; + const uint64_t size = size_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET); + const uint64_t capacity = + capacity_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET); + if (size == LLDB_INVALID_OFFSET || capacity == LLDB_INVALID_OFFSET || + capacity < size) + return {}; + return std::make_pair(size, location_sp); } bool lldb_private::formatters::LibcxxWStringSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options) { - uint64_t size = 0; - ValueObjectSP location_sp; - if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) + auto string_info = ExtractLibcxxStringInfo(valobj); + if (!string_info) return false; + uint64_t size; + ValueObjectSP location_sp; + std::tie(size, location_sp) = *string_info; + if (size == 0) { stream.Printf("L\"\""); return true; @@ -574,10 +577,8 @@ if (!location_sp) return false; - DataExtractor extractor; StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); - if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); if (size > max_size) { @@ -585,6 +586,8 @@ options.SetIsTruncated(true); } } + + DataExtractor extractor; const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size); if (bytes_read < size) return false; @@ -632,10 +635,13 @@ bool LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options, std::string prefix_token) { - uint64_t size = 0; - ValueObjectSP location_sp; - if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) + auto string_info = ExtractLibcxxStringInfo(valobj); + if (!string_info) return false; + uint64_t size; + ValueObjectSP location_sp; + std::tie(size, location_sp) = *string_info; + if (size == 0) { stream.Printf("\"\""); return true; @@ -646,7 +652,6 @@ StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); - DataExtractor extractor; if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); if (size > max_size) { @@ -654,18 +659,18 @@ options.SetIsTruncated(true); } } + + DataExtractor extractor; const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size); if (bytes_read < size) return false; options.SetData(extractor); options.SetStream(&stream); - if (prefix_token.empty()) options.SetPrefixToken(nullptr); else options.SetPrefixToken(prefix_token); - options.SetQuote('"'); options.SetSourceSize(size); options.SetBinaryZeroIsTerminator(false);