Michael137 created this revision.
Michael137 added reviewers: aprantl, jingham.
Herald added a project: All.
Michael137 requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

(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


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D148531

Files:
  lldb/examples/synthetic/libcxx.py
  
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

Index: lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/deque/main.cpp
===================================================================
--- /dev/null
+++ 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;
+}
Index: lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/deque/TestDataFormatterLibcxxDeque.py
===================================================================
--- /dev/null
+++ 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'])
Index: lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/deque/Makefile
===================================================================
--- /dev/null
+++ 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
Index: lldb/examples/synthetic/libcxx.py
===================================================================
--- lldb/examples/synthetic/libcxx.py
+++ lldb/examples/synthetic/libcxx.py
@@ -649,7 +649,12 @@
     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>
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
  • [Lldb-commits] [PATCH] D1485... Michael Buch via Phabricator via lldb-commits

Reply via email to