[Lldb-commits] [lldb] 1414a5b - [lldb][DataFormatter] Fix libcxx std::deque formatter for references and pointers

Michael Buch via lldb-commits lldb-commits at lists.llvm.org
Mon Apr 17 13:32:32 PDT 2023


Author: Michael Buch
Date: 2023-04-17T21:31:30+01:00
New Revision: 1414a5bdfeff3dbbbaae9816ef4017c81112c3c0

URL: https://github.com/llvm/llvm-project/commit/1414a5bdfeff3dbbbaae9816ef4017c81112c3c0
DIFF: https://github.com/llvm/llvm-project/commit/1414a5bdfeff3dbbbaae9816ef4017c81112c3c0.diff

LOG: [lldb][DataFormatter] Fix libcxx std::deque formatter for references and pointers

(Addresses GH#62153)

The `SBType` APIs to retrieve details about template arguments,
such as `GetTemplateArgumentType` or `GetTemplateArgumentKind`
don't "desugar" LValueReferences/RValueReferences or pointers.
So when we try to format a `std::deque&`, the python call to
`GetTemplateArgumentType` fails to get a type, leading to
an `element_size` of `0` and a division-by-zero python exception
(which gets caught by the summary provider silently). This leads
to the contents of such `std::deque&` to be printed incorrectly.

This patch dereferences the reference/pointer before calling
into the above SBAPIs.

**Testing**

* Add API test

Differential Revision: https://reviews.llvm.org/D148531

Added: 
    lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/deque/Makefile
    lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/deque/TestDataFormatterLibcxxDeque.py
    lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/deque/main.cpp

Modified: 
    lldb/examples/synthetic/libcxx.py

Removed: 
    


################################################################################
diff  --git a/lldb/examples/synthetic/libcxx.py b/lldb/examples/synthetic/libcxx.py
index 531d26784afc2..eb26829e2ed02 100644
--- a/lldb/examples/synthetic/libcxx.py
+++ b/lldb/examples/synthetic/libcxx.py
@@ -649,7 +649,12 @@ def __init__(self, valobj, d):
     def find_block_size(self):
         # in order to use the deque we must have the block size, or else
         # it's impossible to know what memory addresses are valid
-        self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
+        obj_type = self.valobj.GetType()
+        if obj_type.IsReferenceType():
+            obj_type = obj_type.GetDereferencedType()
+        elif obj_type.IsPointerType():
+            obj_type = obj_type.GetPointeeType()
+        self.element_type = obj_type.GetTemplateArgumentType(0)
         self.element_size = self.element_type.GetByteSize()
         # The code says this, but there must be a better way:
         # template <class _Tp, class _Allocator>

diff  --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/deque/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/deque/Makefile
new file mode 100644
index 0000000000000..c5ac05605bdcb
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/deque/Makefile
@@ -0,0 +1,4 @@
+USE_LIBCPP := 1
+CXX_SOURCES := main.cpp
+
+include Makefile.rules

diff  --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/deque/TestDataFormatterLibcxxDeque.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/deque/TestDataFormatterLibcxxDeque.py
new file mode 100644
index 0000000000000..9d4c25e44ca95
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/deque/TestDataFormatterLibcxxDeque.py
@@ -0,0 +1,75 @@
+"""
+Test LLDB's data formatter for libcxx's std::deque.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class LibcxxDequeDataFormatterTestCase(TestBase):
+
+    def check_numbers(self, var_name):
+        self.expect("frame variable " + var_name,
+                    substrs=[var_name + ' = size=7',
+                             '[0] = 1',
+                             '[1] = 12',
+                             '[2] = 123',
+                             '[3] = 1234',
+                             '[4] = 12345',
+                             '[5] = 123456',
+                             '[6] = 1234567',
+                             '}'])
+
+        self.expect_expr(var_name, result_summary="size=7", result_children=[
+            ValueCheck(value="1"),
+            ValueCheck(value="12"),
+            ValueCheck(value="123"),
+            ValueCheck(value="1234"),
+            ValueCheck(value="12345"),
+            ValueCheck(value="123456"),
+            ValueCheck(value="1234567"),
+        ])
+
+    @add_test_categories(["libc++"])
+    def test_with_run_command(self):
+        """Test basic formatting of std::deque"""
+        self.build()
+        (self.target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+            self, "break here", lldb.SBFileSpec("main.cpp", False))
+
+        self.expect("frame variable numbers",
+                    substrs=['numbers = size=0'])
+
+        lldbutil.continue_to_breakpoint(process, bkpt)
+
+        # first value added
+        self.expect("frame variable numbers",
+                    substrs=['numbers = size=1',
+                             '[0] = 1',
+                             '}'])
+
+        # add remaining values
+        lldbutil.continue_to_breakpoint(process, bkpt)
+
+        self.check_numbers("numbers")
+
+        # clear out the deque
+        lldbutil.continue_to_breakpoint(process, bkpt)
+
+        self.expect("frame variable numbers",
+                    substrs=['numbers = size=0'])
+
+    @add_test_categories(["libc++"])
+    def test_ref_and_ptr(self):
+        """Test formatting of std::deque& and std::deque*"""
+        self.build()
+        (self.target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+            self, "stop here", lldb.SBFileSpec("main.cpp", False))
+
+        # The reference should display the same was as the value did
+        self.check_numbers("ref")
+
+        # The pointer should just show the right number of elements:
+        self.expect("frame variable ptr", substrs=['ptr =', ' size=7'])
+        self.expect("expression ptr", substrs=['$', 'size=7'])

diff  --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/deque/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/deque/main.cpp
new file mode 100644
index 0000000000000..025c823d1f5b6
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/deque/main.cpp
@@ -0,0 +1,30 @@
+#include <cstdio>
+#include <deque>
+typedef std::deque<int> int_deq;
+
+void by_ref_and_ptr(std::deque<int> &ref, std::deque<int> *ptr) {
+  printf("stop here");
+  return;
+}
+
+int main() {
+  int_deq numbers;
+  printf("break here");
+
+  (numbers.push_back(1));
+  printf("break here");
+
+  (numbers.push_back(12));
+  (numbers.push_back(123));
+  (numbers.push_back(1234));
+  (numbers.push_back(12345));
+  (numbers.push_back(123456));
+  (numbers.push_back(1234567));
+  by_ref_and_ptr(numbers, &numbers);
+  printf("break here");
+
+  numbers.clear();
+  printf("break here");
+
+  return 0;
+}


        


More information about the lldb-commits mailing list