diff options
| author | Enrico Granata <egranata@apple.com> | 2014-01-27 21:31:26 +0000 | 
|---|---|---|
| committer | Enrico Granata <egranata@apple.com> | 2014-01-27 21:31:26 +0000 | 
| commit | 5000ee16f6eb6177e98570e786e6b4be050399b3 (patch) | |
| tree | 4ecd64f0a55d36af16a82034d09577fe24984687 | |
| parent | 9f37737311b90a9b60883184f0130c20d7a92dd3 (diff) | |
| download | bcm5719-llvm-5000ee16f6eb6177e98570e786e6b4be050399b3.tar.gz bcm5719-llvm-5000ee16f6eb6177e98570e786e6b4be050399b3.zip  | |
<rdar://problem/15776874>
ValueObjectPrinter could enter an infinite loop while trying to display an aptly formed ValueObject: a reference, with a child of some pointer type, such that the pointees chain ended up pointing back to some part of itself - a pointer to itself being the simplest such case
Fixed here by only setting a pointer depth when needed, and ensuring that we won't overflow and wrap the pointer depth when it's zero.
llvm-svn: 200247
4 files changed, 84 insertions, 3 deletions
diff --git a/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/lldb/source/DataFormatters/ValueObjectPrinter.cpp index f8a9151b4a6..dca80af812d 100644 --- a/lldb/source/DataFormatters/ValueObjectPrinter.cpp +++ b/lldb/source/DataFormatters/ValueObjectPrinter.cpp @@ -403,7 +403,6 @@ ValueObjectPrinter::ShouldPrintChildren (bool is_failed_description,          // Use a new temporary pointer depth in case we override the          // current pointer depth below... -        uint32_t curr_ptr_depth = m_ptr_depth;          if (is_ptr || is_ref)          { @@ -413,7 +412,7 @@ ValueObjectPrinter::ShouldPrintChildren (bool is_failed_description,              if (m_valobj->GetPointerValue (&ptr_address_type) == 0)                  return false; -            else if (is_ref && m_curr_depth == 0) +            else if (is_ref && m_curr_depth == 0 && curr_ptr_depth == 0)              {                  // If this is the root object (depth is zero) that we are showing                  // and it is a reference, and no pointer depth has been supplied @@ -468,7 +467,7 @@ ValueObjectPrinter::PrintChild (ValueObjectSP child_sp,          ValueObjectPrinter child_printer(child_sp.get(),                                           m_stream,                                           child_options, -                                         (IsPtr() || IsRef()) ? curr_ptr_depth - 1 : curr_ptr_depth, +                                         (IsPtr() || IsRef()) && curr_ptr_depth >= 1 ? curr_ptr_depth - 1 : curr_ptr_depth,                                           m_curr_depth + 1);          child_printer.PrintValueObject();      } diff --git a/lldb/test/functionalities/data-formatter/refpointer-recursion/Makefile b/lldb/test/functionalities/data-formatter/refpointer-recursion/Makefile new file mode 100644 index 00000000000..314f1cb2f07 --- /dev/null +++ b/lldb/test/functionalities/data-formatter/refpointer-recursion/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +CXX_SOURCES := main.cpp + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/functionalities/data-formatter/refpointer-recursion/TestDataFormatterRefPtrRecursion.py b/lldb/test/functionalities/data-formatter/refpointer-recursion/TestDataFormatterRefPtrRecursion.py new file mode 100644 index 00000000000..e1b195570d0 --- /dev/null +++ b/lldb/test/functionalities/data-formatter/refpointer-recursion/TestDataFormatterRefPtrRecursion.py @@ -0,0 +1,56 @@ +""" +Test that ValueObjectPrinter does not cause an infinite loop when a reference to a struct that contains a pointer to itself is printed. +""" + +import os, time +import unittest2 +import lldb +from lldbtest import * +import lldbutil + +class DataFormatterRefPtrRecursionTestCase(TestBase): + +    mydir = TestBase.compute_mydir(__file__) + +    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") +    @dsym_test +    def test_with_dsym_and_run_command(self): +        """Test that ValueObjectPrinter does not cause an infinite loop when a reference to a struct that contains a pointer to itself is printed.""" +        self.buildDsym() +        self.data_formatter_commands() + +    @dwarf_test +    def test_with_dwarf_and_run_command(self): +        """Test that ValueObjectPrinter does not cause an infinite loop when a reference to a struct that contains a pointer to itself is printed.""" +        self.buildDwarf() +        self.data_formatter_commands() + +    def setUp(self): +        # 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.') + +    def data_formatter_commands(self): +        """Test that ValueObjectPrinter does not cause an infinite loop when a reference to a struct that contains a pointer to itself is printed.""" +        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) + +        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True) + +        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']) + +        self.expect("frame variable foo", substrs = []); +        self.expect("frame variable foo --ptr-depth=1", substrs = ['ID = 1']); +        self.expect("frame variable foo --ptr-depth=2", substrs = ['ID = 1']); +        self.expect("frame variable foo --ptr-depth=3", substrs = ['ID = 1']); + +if __name__ == '__main__': +    import atexit +    lldb.SBDebugger.Initialize() +    atexit.register(lambda: lldb.SBDebugger.Terminate()) +    unittest2.main() diff --git a/lldb/test/functionalities/data-formatter/refpointer-recursion/main.cpp b/lldb/test/functionalities/data-formatter/refpointer-recursion/main.cpp new file mode 100644 index 00000000000..4b576bd266d --- /dev/null +++ b/lldb/test/functionalities/data-formatter/refpointer-recursion/main.cpp @@ -0,0 +1,21 @@ +int _ID = 0; + +class Foo { +	public: +		Foo *next; +		int ID; +	 +	Foo () : next(0), ID(++_ID) {} +}; + +int evalFoo(Foo& foo) +{ +	return foo.ID; // Set break point at this line. +} + +int main() { +	Foo f; +	f.next = &f; +	return evalFoo(f); +} +  | 

