Author: sivachandra Date: Wed Sep 23 12:47:08 2015 New Revision: 248401 URL: http://llvm.org/viewvc/llvm-project?rev=248401&view=rev Log: DWARFASTParserClang::CompleteTypeFromDWARF: Handle incomplete baseclass or child
Summary: With this change DWARFASTParserClang::CompleteTypeFromDWARF returns false if DWARFASTParserClang::ParseChildMembers returns false. Similarly, it returns false if any base class is of an incomplete type. 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". Reviewers: clayborg Subscribers: lldb-commits Differential Revision: http://reviews.llvm.org/D13066 Added: lldb/trunk/test/lang/cpp/incomplete-types/ lldb/trunk/test/lang/cpp/incomplete-types/Makefile lldb/trunk/test/lang/cpp/incomplete-types/TestCppIncompleteTypes.py lldb/trunk/test/lang/cpp/incomplete-types/length.cpp lldb/trunk/test/lang/cpp/incomplete-types/length.h lldb/trunk/test/lang/cpp/incomplete-types/main.cpp Modified: lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h Modified: lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp?rev=248401&r1=248400&r2=248401&view=diff ============================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp (original) +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp Wed Sep 23 12:47:08 2015 @@ -1770,7 +1770,6 @@ DWARFASTParserClang::CompleteTypeFromDWA type->GetName().AsCString()); assert (clang_type); DWARFAttributes attributes; - switch (tag) { case DW_TAG_structure_type: @@ -1817,17 +1816,25 @@ DWARFASTParserClang::CompleteTypeFromDWA 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)) + { + auto module = dwarf->GetObjectFile()->GetModule(); + module->ReportError (":: Class %s has members with incomplete type.", die.GetName()); + if (die.GetCU()->GetProducer() == DWARFCompileUnit::eProducerClang) + module->ReportError(":: Try compiling the source file with -fno-limit-debug-info."); + + return false; + } // Now parse any methods if there were any... size_t num_functions = member_function_dies.Size(); @@ -1902,7 +1909,6 @@ DWARFASTParserClang::CompleteTypeFromDWA // Make sure all base classes refer to complete types and not // forward declarations. If we don't do this, clang will crash // with an assertion in the call to clang_type.SetBaseClassesForClassType() - bool base_class_error = false; for (auto &base_class : base_classes) { clang::TypeSourceInfo *type_source_info = base_class->getTypeSourceInfo(); @@ -1911,23 +1917,15 @@ DWARFASTParserClang::CompleteTypeFromDWA CompilerType base_class_type (&m_ast, type_source_info->getType().getAsOpaquePtr()); if (base_class_type.GetCompleteType() == false) { - if (!base_class_error) - { - dwarf->GetObjectFile()->GetModule()->ReportError ("DWARF DIE at 0x%8.8x for class '%s' has a base class '%s' that is a forward declaration, not a complete definition.\nPlease file a bug against the compiler and include the preprocessed output for %s", - die.GetOffset(), - die.GetName(), - base_class_type.GetTypeName().GetCString(), - sc.comp_unit ? sc.comp_unit->GetPath().c_str() : "the source file"); - } - // We have no choice other than to pretend that the base class - // is complete. If we don't do this, clang will crash when we - // call setBases() inside of "clang_type.SetBaseClassesForClassType()" - // below. Since we provide layout assistance, all ivars in this - // class and other classes will be fine, this is the best we can do - // short of crashing. + auto module = dwarf->GetObjectFile()->GetModule(); + module->ReportError ( + ":: Class '%s' has a base class '%s' which does not have a complete definition.", + die.GetName(), + base_class_type.GetTypeName().GetCString()); + if (die.GetCU()->GetProducer() == DWARFCompileUnit::eProducerClang) + module->ReportError (":: Try compiling the source file with -fno-limit-debug-info."); - ClangASTContext::StartTagDeclarationDefinition (base_class_type); - ClangASTContext::CompleteTagDeclarationDefinition (base_class_type); + return false; } } } @@ -2354,7 +2352,7 @@ DWARFASTParserClang::ParseFunctionFromDW } -size_t +bool DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc, const DWARFDIE &parent_die, CompilerType &class_clang_type, @@ -2370,7 +2368,7 @@ DWARFASTParserClang::ParseChildMembers ( 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 +2702,8 @@ DWARFASTParserClang::ParseChildMembers ( } 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 +2926,7 @@ DWARFASTParserClang::ParseChildMembers ( } } - return count; + return incomplete_member_info_count == 0; } Modified: lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h?rev=248401&r1=248400&r2=248401&view=diff ============================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h (original) +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h Wed Sep 23 12:47:08 2015 @@ -104,7 +104,7 @@ protected: 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, Added: lldb/trunk/test/lang/cpp/incomplete-types/Makefile URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/cpp/incomplete-types/Makefile?rev=248401&view=auto ============================================================================== --- lldb/trunk/test/lang/cpp/incomplete-types/Makefile (added) +++ lldb/trunk/test/lang/cpp/incomplete-types/Makefile Wed Sep 23 12:47:08 2015 @@ -0,0 +1,32 @@ +LEVEL = ../../../make + +CXX_SOURCES = main.cpp length.cpp + +CFLAGS_LIMIT = -g -O0 -c +CFLAGS_NO_LIMIT = -g -O0 -c + +ifneq (,$(findstring clang,$(CC))) + CFLAGS_LIMIT += -flimit-debug-info + CFLAGS_NO_LIMIT += -fno-limit-debug-info +endif + +all: limit nolimit + +limit: main.o length_limit.o + $(CXX) main.o length_limit.o -o limit + +nolimit: main.o length_nolimit.o + $(CXX) main.o length_nolimit.o -o nolimit + +main.o: main.cpp + $(CXX) $(CFLAGS_LIMIT) main.cpp -o main.o + +length_limit.o: length.cpp + $(CXX) $(CFLAGS_LIMIT) length.cpp -o length_limit.o + +length_nolimit.o: length.cpp + $(CXX) $(CFLAGS_NO_LIMIT) length.cpp -o length_nolimit.o + +clean: OBJECTS += limit nolimit length_limit.o length_nolimit.o + +include $(LEVEL)/Makefile.rules Added: lldb/trunk/test/lang/cpp/incomplete-types/TestCppIncompleteTypes.py URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/cpp/incomplete-types/TestCppIncompleteTypes.py?rev=248401&view=auto ============================================================================== --- lldb/trunk/test/lang/cpp/incomplete-types/TestCppIncompleteTypes.py (added) +++ lldb/trunk/test/lang/cpp/incomplete-types/TestCppIncompleteTypes.py Wed Sep 23 12:47:08 2015 @@ -0,0 +1,75 @@ +import lldb +from lldbtest import * +import lldbutil + +class TestCppIncompleteTypes(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @dwarf_test + @skipIfGcc + def test_with_dwarf_limit_debug_info(self): + self.buildDwarf() + frame = self.get_test_frame('limit') + + 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") + + value_s = frame.EvaluateExpression("s") + self.assertTrue(value_s.IsValid(), "'expr s' results in a valid SBValue object") + self.assertFalse(value_s.GetError().Success(), "'expr s' results in an error, but LLDB does not crash") + + @dwarf_test + @skipIfGcc + def test_with_dwarf_partial_limit_debug_info(self): + self.buildDwarf() + frame = self.get_test_frame('nolimit') + + value_f = frame.EvaluateExpression("f") + self.assertTrue(value_f.IsValid(), "'expr f' results in a valid SBValue object") + self.assertTrue(value_f.GetError().Success(), "'expr f' is successful") + + value_s = frame.EvaluateExpression("s") + self.assertTrue(value_s.IsValid(), "'expr s' results in a valid SBValue object") + self.assertTrue(value_s.GetError().Success(), "'expr s' is successful") + + def setUp(self): + TestBase.setUp(self) + + def get_test_frame(self, exe): + # 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_path = os.path.join(cwd, exe) + + # 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 + return thread.GetSelectedFrame() + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() Added: lldb/trunk/test/lang/cpp/incomplete-types/length.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/cpp/incomplete-types/length.cpp?rev=248401&view=auto ============================================================================== --- lldb/trunk/test/lang/cpp/incomplete-types/length.cpp (added) +++ lldb/trunk/test/lang/cpp/incomplete-types/length.cpp Wed Sep 23 12:47:08 2015 @@ -0,0 +1,8 @@ + +#include "length.h" + +size_t +length (const std::string &str) +{ + return str.length(); +} Added: lldb/trunk/test/lang/cpp/incomplete-types/length.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/cpp/incomplete-types/length.h?rev=248401&view=auto ============================================================================== --- lldb/trunk/test/lang/cpp/incomplete-types/length.h (added) +++ lldb/trunk/test/lang/cpp/incomplete-types/length.h Wed Sep 23 12:47:08 2015 @@ -0,0 +1,8 @@ +#ifndef __LENGTH_H__ +#define __LENGTH_H__ + +#include <string> + +size_t length (const std::string &str); + +#endif Added: lldb/trunk/test/lang/cpp/incomplete-types/main.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/cpp/incomplete-types/main.cpp?rev=248401&view=auto ============================================================================== --- lldb/trunk/test/lang/cpp/incomplete-types/main.cpp (added) +++ lldb/trunk/test/lang/cpp/incomplete-types/main.cpp Wed Sep 23 12:47:08 2015 @@ -0,0 +1,23 @@ + +#include "length.h" + +class Foo { +public: + Foo(std::string x) : s(x) {} + +private: + std::string s; +}; + +class MyString : public std::string { +public: + MyString(std::string x) : std::string(x) {} +}; + +int main() +{ + Foo f("qwerty"); + MyString s("qwerty"); + + return length(s); // break here +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits