Skip to content

[lldb] Fix libstdc++ std::string formatter after #147835 #152993

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 1 commit into from
Aug 11, 2025

Conversation

DavidSpickett
Copy link
Collaborator

@DavidSpickett DavidSpickett commented Aug 11, 2025

#147835 made changes that caused libstdc++ std::string tests to fail:

======================================================================
FAIL: test_unavailable_summary_libstdcxx_dwo (TestDataFormatterStdString.StdStringDataFormatterTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 1805, in test_method
    return attrvalue(self)
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py", line 223, in test_unavailable_summary_libstdcxx
    self.do_test_summary_unavailable()
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py", line 213, in do_test_summary_unavailable
    self.assertEqual(summary, "Summary Unavailable", "No summary for bad value")
AssertionError: '(null)' != 'Summary Unavailable'
- (null)
+ Summary Unavailable
 : No summary for bad value
Config=aarch64-/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang
----------------------------------------------------------------------

This test constructs an invalid std::string by starting with a null pointer.

Somehow this improvement in Clang uncovered a bug in the formatter. Perhaps because we now know the type of the field we tried to access is char *, so fall back to a C string formatter that produces (null).

The formatter tries to access _M_p and checked whether the resulting ValueObjectSP was null, but not that it did not contain an error value. I think that error value can be there if you are able to access one part of the path, _M_dataplus, but another part fails. Since the layout looks like this:

      struct _Alloc_hider :
      {
	      pointer _M_p; // The actual data.
      };

      _Alloc_hider	_M_dataplus;

      void
      _M_data(pointer __p)
      { _M_dataplus._M_p = __p; }

So I think we were able to read _M_dataplus just by offset, but then failed because it contains, or points to something containing nulls or a null pointer.

Or perhaps an error value means we know what the class member is, but could not read from it.

I found this by comparing with the libcxx formatter, so I've copied the same handling from there to fix the issue.

llvm#147835 made changes that
caused libstdc++ std::string tests to fail:
```
======================================================================
FAIL: test_unavailable_summary_libstdcxx_dwo (TestDataFormatterStdString.StdStringDataFormatterTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 1805, in test_method
    return attrvalue(self)
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py", line 223, in test_unavailable_summary_libstdcxx
    self.do_test_summary_unavailable()
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py", line 213, in do_test_summary_unavailable
    self.assertEqual(summary, "Summary Unavailable", "No summary for bad value")
AssertionError: '(null)' != 'Summary Unavailable'
- (null)
+ Summary Unavailable
 : No summary for bad value
Config=aarch64-/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang
----------------------------------------------------------------------
```

This test constructs an invalid std::string by starting with a null pointer.

Somehow this improvement in Clang uncovered a bug in the formatter. The formatter
tries to access `_M_p` and checked whether the resulting ValueObjectSP was null,
but not that it did not contain an error value.

I think that error value can be there if you are able to access one part
of the path, `_M_dataplus`, but another part fails. Since the layout looks like this:
```
      struct _Alloc_hider :
      {
	      pointer _M_p; // The actual data.
      };

      _Alloc_hider	_M_dataplus;

      void
      _M_data(pointer __p)
      { _M_dataplus._M_p = __p; }
```
So I think we were able to read `_M_dataplus` just by offset, but
then failed because it contains, or points to something containing
nulls or a null pointer.

Or perhaps an error value means we know what the class member is,
but could not read from it.

I found this by comparing with the libcxx formatter, so I've copied
the same handling from there to fix the issue.
@llvmbot
Copy link
Member

llvmbot commented Aug 11, 2025

@llvm/pr-subscribers-lldb

Author: David Spickett (DavidSpickett)

Changes

#147835 made changes that caused libstdc++ std::string tests to fail:

======================================================================
FAIL: test_unavailable_summary_libstdcxx_dwo (TestDataFormatterStdString.StdStringDataFormatterTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 1805, in test_method
    return attrvalue(self)
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py", line 223, in test_unavailable_summary_libstdcxx
    self.do_test_summary_unavailable()
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py", line 213, in do_test_summary_unavailable
    self.assertEqual(summary, "Summary Unavailable", "No summary for bad value")
AssertionError: '(null)' != 'Summary Unavailable'
- (null)
+ Summary Unavailable
 : No summary for bad value
Config=aarch64-/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang
----------------------------------------------------------------------

This test constructs an invalid std::string by starting with a null pointer.

Somehow this improvement in Clang uncovered a bug in the formatter. The formatter tries to access _M_p and checked whether the resulting ValueObjectSP was null, but not that it did not contain an error value.

I think that error value can be there if you are able to access one part of the path, _M_dataplus, but another part fails. Since the layout looks like this:

      struct _Alloc_hider :
      {
	      pointer _M_p; // The actual data.
      };

      _Alloc_hider	_M_dataplus;

      void
      _M_data(pointer __p)
      { _M_dataplus._M_p = __p; }

So I think we were able to read _M_dataplus just by offset, but then failed because it contains, or points to something containing nulls or a null pointer.

Or perhaps an error value means we know what the class member is, but could not read from it.

I found this by comparing with the libcxx formatter, so I've copied the same handling from there to fix the issue.


Full diff: https://github.com/llvm/llvm-project/pull/152993.diff

1 Files Affected:

  • (modified) lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp (+4-3)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
index 595e835b37df9..f4a695e036999 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
@@ -241,10 +241,11 @@ VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
 bool lldb_private::formatters::LibStdcppStringSummaryProvider(
     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
   ValueObjectSP ptr = valobj.GetChildAtNamePath({"_M_dataplus", "_M_p"});
-  if (!ptr)
-    return false;
+  if (!ptr || !ptr->GetError().Success())
+    stream << "Summary Unavailable";
+  else
+    stream << ptr->GetSummaryAsCString();
 
-  stream << ptr->GetSummaryAsCString();
   return true;
 }
 

Copy link
Member

@Michael137 Michael137 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM thanks! Checking the error seems like the right thing to do regardless of what caused the issue

@DavidSpickett
Copy link
Collaborator Author

AssertionError: '(null)' != 'Summary Unavailable'

I guess that before we didn't have the full type of this nested struct member. Then clang made improvements so we did, and then knew to format it as a C string.

@DavidSpickett DavidSpickett merged commit f23d2ee into llvm:main Aug 11, 2025
10 of 11 checks passed
@DavidSpickett DavidSpickett deleted the lldb-cpp-string branch August 11, 2025 11:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants