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 @@ -558,12 +558,14 @@ // TODO: Support big-endian architectures. static llvm::Optional> ExtractLibcxxStringInfo(ValueObject &valobj) { - ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0})); - if (!D) + ValueObjectSP dataval_sp(valobj.GetChildAtIndexPath({0, 0, 0, 0})); + if (!dataval_sp) + return {}; + if (!dataval_sp->GetError().Success()) return {}; ValueObjectSP layout_decider( - D->GetChildAtIndexPath(llvm::ArrayRef({0, 0}))); + dataval_sp->GetChildAtIndexPath(llvm::ArrayRef({0, 0}))); // this child should exist if (!layout_decider) @@ -581,12 +583,12 @@ : eLibcxxStringLayoutModeCSD; uint64_t size_mode_value = 0; - if (ValueObjectSP is_long = D->GetChildAtNamePath( + if (ValueObjectSP is_long = dataval_sp->GetChildAtNamePath( {ConstString("__s"), ConstString("__is_long_")})) { using_bitmasks = false; short_mode = !is_long->GetValueAsUnsigned(/*fail_value=*/0); if (ValueObjectSP size_member = - D->GetChildAtNamePath({ConstString("__s"), ConstString("__size_")})) + dataval_sp->GetChildAtNamePath({ConstString("__s"), ConstString("__size_")})) size = size_member->GetValueAsUnsigned(/*fail_value=*/0); else return {}; @@ -599,7 +601,7 @@ }; ValueObjectSP size_mode; for (llvm::ArrayRef loc : size_mode_locations) { - size_mode = D->GetChildAtIndexPath(loc); + size_mode = dataval_sp->GetChildAtIndexPath(loc); if (size_mode && size_mode->GetName() == g_size_name) break; } @@ -610,7 +612,7 @@ size_mode_value = (size_mode->GetValueAsUnsigned(0)); short_mode = ((size_mode_value & 0x80) == 0); } else { - ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 0, 0})); + ValueObjectSP size_mode(dataval_sp->GetChildAtIndexPath({1, 0, 0})); if (!size_mode) return {}; @@ -619,10 +621,10 @@ } if (short_mode) { - ValueObjectSP s(D->GetChildAtIndex(1, true)); - if (!s) + ValueObjectSP short_sp(dataval_sp->GetChildAtIndex(1, true)); + if (!short_sp) return {}; - ValueObjectSP location_sp = s->GetChildAtIndex( + ValueObjectSP location_sp = short_sp->GetChildAtIndex( (layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true); if (using_bitmasks) size = (layout == eLibcxxStringLayoutModeDSC) @@ -642,7 +644,7 @@ return std::make_pair(size, location_sp); } - ValueObjectSP l(D->GetChildAtIndex(0, true)); + ValueObjectSP l(dataval_sp->GetChildAtIndex(0, true)); if (!l) return {}; // we can use the layout_decider object as the data pointer diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py @@ -19,7 +19,7 @@ # Call super's setUp(). TestBase.setUp(self) # Find the line number to break at. - self.line = line_number('main.cpp', '// Set break point at this line.') + self.main_spec = lldb.SBFileSpec("main.cpp") self.namespace = 'std' @add_test_categories(["libc++"]) @@ -30,17 +30,11 @@ def test_with_run_command(self): """Test that that file and class static variables display correctly.""" self.build() - self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) - lldbutil.run_break_set_by_file_and_line( - self, "main.cpp", self.line, num_expected_locations=-1) - - self.runCmd("run", RUN_SUCCEEDED) - - # The stop reason of the thread should be breakpoint. - self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, - substrs=['stopped', - 'stop reason = breakpoint']) + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + "Set break point at this line.", + self.main_spec) + frame = thread.frames[0] # This is the function to remove the custom formats in order to have a # clean slate for the next test case. @@ -83,9 +77,9 @@ '(%s::string *) null_str = nullptr'%ns, ]) - self.runCmd("n") + thread.StepOver() - TheVeryLongOne = self.frame().FindVariable("TheVeryLongOne") + TheVeryLongOne = frame.FindVariable("TheVeryLongOne") summaryOptions = lldb.SBTypeSummaryOptions() summaryOptions.SetCapping(lldb.eTypeSummaryUncapped) uncappedSummaryStream = lldb.SBStream() @@ -129,3 +123,15 @@ self.expect("frame variable garbage3", substrs=[r'garbage3 = "\xf0\xf0"']) self.expect("frame variable garbage4", substrs=['garbage4 = Summary Unavailable']) self.expect("frame variable garbage5", substrs=['garbage5 = Summary Unavailable']) + + # Finally, make sure that if the string is not readable, we give an error: + bkpt_2 = target.BreakpointCreateBySourceRegex("Break here to look at bad string", self.main_spec) + self.assertEqual(bkpt_2.GetNumLocations(), 1, "Got one location") + threads = lldbutil.continue_to_breakpoint(process, bkpt_2) + self.assertEqual(len(threads), 1, "Stopped at second breakpoint") + frame = threads[0].frames[0] + var = frame.FindVariable("in_str") + self.assertTrue(var.GetError().Success(), "Made variable") + summary = var.GetSummary() + self.assertEqual(summary, "Summary Unavailable", "No summary for bad value") + diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/main.cpp --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/main.cpp @@ -57,6 +57,11 @@ uint64_t data = 0xfffffffffffffffeULL; } garbage_string_long_mode4; +size_t touch_string(std::string &in_str) +{ + return in_str.size(); // Break here to look at bad string +} + int main() { std::wstring wempty(L""); @@ -93,5 +98,7 @@ #endif S.assign(L"!!!!!"); // Set break point at this line. + std::string *not_a_string = (std::string *) 0x0; + touch_string(*not_a_string); return 0; }