sivachandra created this revision.
sivachandra added a reviewer: clayborg.
sivachandra added a subscriber: lldb-commits.

The return value is false if any of the child members have incomplete
type info. This helps in cases like these:

class Foo
{
public:
  std::string str;
};

...

Foo f;

If a file with the above code is compiled with a modern clang but without
the -fno-limit-debug-info (or similar) option, then the DWARF has only
a forward declration for std::string. In which case, the type for
"class Foo" cannot be completed. If LLDB does not detect that a child
member has incomplete type, then it wrongly conveys to clang (the LLDB
compiler) that "class Foo" is complete, and consequently crashes due to
an assertion failure in clang when running commands like "p f" or
"frame var f".

After the change to DWARFASTParserClang::ParseChildMember,
DWARFASTParserClang::CompleteTypeFromDWARF returns false if
DWARFASTParserClang::ParseChildMember returns false.

http://reviews.llvm.org/D13066

Files:
  source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
  source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
  test/lang/cpp/incomplete-types/Makefile
  test/lang/cpp/incomplete-types/TestCppIncompleteTypes.py
  test/lang/cpp/incomplete-types/main.cpp

Index: test/lang/cpp/incomplete-types/main.cpp
===================================================================
--- /dev/null
+++ test/lang/cpp/incomplete-types/main.cpp
@@ -0,0 +1,15 @@
+#include <string>
+
+class Foo {
+public:
+    Foo(std::string x) : s(x) {}
+
+private:
+    std::string s;
+};
+
+int main()
+{
+    Foo f("qwerty");
+    return 0; // break here
+}
Index: test/lang/cpp/incomplete-types/TestCppIncompleteTypes.py
===================================================================
--- /dev/null
+++ test/lang/cpp/incomplete-types/TestCppIncompleteTypes.py
@@ -0,0 +1,60 @@
+import lldb
+from lldbtest import *
+import lldbutil
+
+class TestCppChainedCalls(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @dwarf_test
+    @skipIfDarwin
+    @skipIfGcc
+    def test_with_dwarf_and_run_command(self):
+        self.buildDwarf()
+        self.check()
+
+    def setUp(self):
+        TestBase.setUp(self)
+
+    def check(self):
+        # Get main source file
+        src_file = "main.cpp"
+        src_file_spec = lldb.SBFileSpec(src_file)
+        self.assertTrue(src_file_spec.IsValid(), "Main source file")
+
+        # Get the path of the executable
+        cwd = os.getcwd()
+        exe_file = "a.out"
+        exe_path  = os.path.join(cwd, exe_file)
+
+        # Load the executable
+        target = self.dbg.CreateTarget(exe_path)
+        self.assertTrue(target.IsValid(), VALID_TARGET)
+
+        # Break on main function
+        main_breakpoint = target.BreakpointCreateBySourceRegex("break here", src_file_spec)
+        self.assertTrue(main_breakpoint.IsValid() and main_breakpoint.GetNumLocations() >= 1, VALID_BREAKPOINT)
+
+        # Launch the process
+        args = None
+        env = None
+        process = target.LaunchSimple(args, env, self.get_process_working_directory())
+        self.assertTrue(process.IsValid(), PROCESS_IS_VALID)
+
+        # Get the thread of the process
+        self.assertTrue(process.GetState() == lldb.eStateStopped, PROCESS_STOPPED)
+        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
+
+        # Get frame for current thread
+        frame = thread.GetSelectedFrame()
+
+        # Test chained calls
+        value_f = frame.EvaluateExpression("f")
+        self.assertTrue(value_f.IsValid(), "'expr f' results in a valid SBValue object")
+        self.assertFalse(value_f.GetError().Success(), "'expr f' results in an error, but LLDB does not crash")
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()
Index: test/lang/cpp/incomplete-types/Makefile
===================================================================
--- /dev/null
+++ test/lang/cpp/incomplete-types/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
+++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
@@ -104,7 +104,7 @@
     ParseTemplateParameterInfos (const DWARFDIE &parent_die,
                                  lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos);
 
-    size_t
+    bool
     ParseChildMembers (const lldb_private::SymbolContext& sc,
                        const DWARFDIE &die,
                        lldb_private::CompilerType &class_clang_type,
Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -1770,7 +1770,6 @@
                                                                          type->GetName().AsCString());
     assert (clang_type);
     DWARFAttributes attributes;
-
     switch (tag)
     {
         case DW_TAG_structure_type:
@@ -1817,17 +1816,18 @@
                     DWARFDIECollection member_function_dies;
 
                     DelayedPropertyList delayed_properties;
-                    ParseChildMembers (sc,
-                                       die,
-                                       clang_type,
-                                       class_language,
-                                       base_classes,
-                                       member_accessibilities,
-                                       member_function_dies,
-                                       delayed_properties,
-                                       default_accessibility,
-                                       is_a_class,
-                                       layout_info);
+                    if (!ParseChildMembers (sc,
+                                            die,
+                                            clang_type,
+                                            class_language,
+                                            base_classes,
+                                            member_accessibilities,
+                                            member_function_dies,
+                                            delayed_properties,
+                                            default_accessibility,
+                                            is_a_class,
+                                            layout_info))
+                        return false;
 
                     // Now parse any methods if there were any...
                     size_t num_functions = member_function_dies.Size();
@@ -2354,7 +2354,7 @@
 }
 
 
-size_t
+bool
 DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc,
                                         const DWARFDIE &parent_die,
                                         CompilerType &class_clang_type,
@@ -2370,7 +2370,7 @@
     if (!parent_die)
         return 0;
 
-    size_t count = 0;
+    uint32_t incomplete_member_info_count = 0;
     uint32_t member_idx = 0;
     BitfieldInfo last_field_info;
 
@@ -2704,6 +2704,8 @@
                                 }
 
                                 CompilerType member_clang_type = member_type->GetLayoutCompilerType ();
+                                if (!member_clang_type.IsCompleteType() && !member_clang_type.GetCompleteType())
+                                    incomplete_member_info_count += 1;
 
                                 {
                                     // Older versions of clang emit array[0] and array[1] in the same way (<rdar://problem/12566646>).
@@ -2926,7 +2928,7 @@
         }
     }
 
-    return count;
+    return incomplete_member_info_count == 0;
 }
 
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to