From cfc8aabb6ddfe55d75ab064423b2ffa6f88f23e3 Mon Sep 17 00:00:00 2001 From: Michael Buch Date: Thu, 20 Mar 2025 14:55:51 +0000 Subject: [PATCH] [lldb][DWARFASTParserClang] Don't complete conflicting Objective-C++ types This patch is a temporary alternative to https://github.com/llvm/llvm-project/pull/130768 If we detect a situation where a forward declaration is C++ and the definition DIE is Objective-C, then just don't try to complete the type (it would crash otherwise). In the long term we might want to add support for completing such types rdar://145959981 --- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 20 +++++- .../DWARF/objcxx-forward-decls.test | 70 +++++++++++++++++++ 2 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 lldb/test/Shell/SymbolFile/DWARF/objcxx-forward-decls.test diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 93a47d748a4e5..67c4e2ada33b7 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -40,6 +40,7 @@ #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" +#include "lldb/lldb-enumerations.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" @@ -2204,6 +2205,22 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die, if (attrs.is_forward_declaration) return true; + const bool type_is_objc_object_or_interface = + TypeSystemClang::IsObjCObjectOrInterfaceType(clang_type); + if (!type_is_objc_object_or_interface && + Language::LanguageIsObjC( + static_cast(die.GetAttributeValueAsUnsigned( + DW_AT_APPLE_runtime_class, eLanguageTypeUnknown)))) { + // The forward declaration was C++ but the definition is Objective-C. + // We currently don't handle such situations. Keep the forward declaration + // without a definition. + LLDB_LOG(GetLog(LLDBLog::Expressions), + "WARNING: Type completion aborted because forward declaration for " + "'{0}' is C++ while definition is Objective-C.", + attrs.name.AsCString("")); + return false; + } + clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE(die, nullptr); // Start the definition if the type is not being defined already. This can @@ -2231,9 +2248,6 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die, default_accessibility, layout_info); // Now parse any methods if there were any... - const bool type_is_objc_object_or_interface = - TypeSystemClang::IsObjCObjectOrInterfaceType(clang_type); - // Now parse any methods if there were any... for (const DWARFDIE &mem : member_function_dies) dwarf->ResolveType(mem); diff --git a/lldb/test/Shell/SymbolFile/DWARF/objcxx-forward-decls.test b/lldb/test/Shell/SymbolFile/DWARF/objcxx-forward-decls.test new file mode 100644 index 0000000000000..30109c2943c9b --- /dev/null +++ b/lldb/test/Shell/SymbolFile/DWARF/objcxx-forward-decls.test @@ -0,0 +1,70 @@ +# REQUIRES: system-darwin + +# In this test we have two CUs with conflicting forward declaration +# depending on the CU language (one is C++ and the other is Objective-C++). +# We are then stopped in the C++ CU and try to print the type, at which +# point LLDB will try to make it into an Clang AST node. If LLDB were to +# interpret the type as C++ instead of Objective-C, we'd violate Clang +# invariants and crash. +# +# RUN: split-file %s %t +# RUN: %clangxx_host -c -g -x objective-c++ %t/request.m -o %t/request_objc.o +# RUN: %clangxx_host -c -g %t/main.cpp -o %t/main.o +# RUN: %clangxx_host %t/main.o %t/request_objc.o -framework Foundation -o %t/a.out +# +# RUN: %lldb %t/a.out \ +# RUN: -o "breakpoint set -p return -X main" \ +# RUN: -o run \ +# RUN: -o "frame variable r" \ +# RUN: -o exit | FileCheck %s +# +# RUN: dsymutil %t/a.out +# +# RUN: %lldb %t/a.out \ +# RUN: -o "breakpoint set -p return -X main" \ +# RUN: -o run \ +# RUN: -o "frame variable r" \ +# RUN: -o exit | FileCheck %s --check-prefix=CHECK-DSYM + +# CHECK: (lldb) frame variable r +# CHECK-NEXT: (Request) ::r = (m_request = "Hello, World!") + +# CHECK-DSYM: (lldb) frame variable r +# CHECK-DSYM-NEXT: (Request) ::r = (m_request = "Hello, World!") + +#--- lib.h +#ifndef LIB_H_IN +#define LIB_H_IN + +#ifdef __OBJC__ +@class NSString; +#else +class NSString; +#endif + +struct Request { + NSString * m_request = nullptr; +}; + +#endif // _H_IN + +#--- main.cpp +#include "lib.h" + +void process(Request *); + +Request r; + +int main() { + process(&r); + return 0; +} + +#--- request.m +#import + +#include "lib.h" + +void process(Request * r) { + r->m_request = @"Hello, World!"; +}