[Lldb-commits] [lldb] [lldb][Expression] Avoid creating ValueObjectSyntheticFilter for incomplete C++ types in ObjC++ targets (PR #153454)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Aug 15 00:43:09 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: Michael Buch (Michael137)
<details>
<summary>Changes</summary>
This patch addresses an infinite recursion that happens when we try to check `HasSyntheticValue` for incomplete C++ types. We're inside of `ValueObject::Dereference` but `TypeSystemClang::GetDereferencedType` failed. When `GetPreferredDisplayLanguage` is `C++` we bail (according to a comment just above the language check this is a workaround). But for Objective-C we continue and create a `ValueObjectSyntheticFilter`, which internally will call back into `ValueObject::Dereference`. Hence the infinite recursion. The reason this happens for `std::vector` in the test-case is that the target was compiled with `Objective-C++`, so we treat it the same that we do Objective-C. This patch works around this issue by skipping this if we're dealing with a pointer to a C++ type.
It's one of those cases where it's awkward for LLDB to know what to do because ObjC++ really does mean ObjC *or* C++.
rdar://158058556
---
Full diff: https://github.com/llvm/llvm-project/pull/153454.diff
7 Files Affected:
- (modified) lldb/include/lldb/Symbol/CompilerType.h (+2)
- (modified) lldb/include/lldb/Symbol/TypeSystem.h (+3)
- (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+20-1)
- (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h (+3)
- (modified) lldb/source/Symbol/CompilerType.cpp (+7)
- (modified) lldb/source/ValueObject/ValueObject.cpp (+2)
- (added) lldb/test/Shell/Expr/TestPrintCXXTypeAsObjCXX.test (+34)
``````````diff
diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h
index df8489a7fe582..f91753afa684c 100644
--- a/lldb/include/lldb/Symbol/CompilerType.h
+++ b/lldb/include/lldb/Symbol/CompilerType.h
@@ -136,6 +136,8 @@ class CompilerType {
bool IsBeingDefined() const;
+ bool IsClassTypeForLanguage(lldb::LanguageType language) const;
+
bool IsCharType() const;
bool IsCompleteType() const;
diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h
index 16a2e0b5a52fb..486aa722992dc 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -160,6 +160,9 @@ class TypeSystem : public PluginInterface,
virtual bool IsCompleteType(lldb::opaque_compiler_type_t type) = 0;
+ virtual bool IsClassTypeForLanguage(lldb::opaque_compiler_type_t type,
+ lldb::LanguageType language) = 0;
+
virtual bool IsDefined(lldb::opaque_compiler_type_t type) = 0;
virtual bool IsFloatingPointType(lldb::opaque_compiler_type_t type,
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index c4a917f59fb88..9ab816d3f27e0 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -80,8 +80,9 @@
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
#include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h"
-#include "Plugins/SymbolFile/PDB/PDBASTParser.h"
#include "Plugins/SymbolFile/NativePDB/PdbAstBuilder.h"
+#include "Plugins/SymbolFile/PDB/PDBASTParser.h"
+#include "lldb/lldb-types.h"
#include <cstdio>
@@ -3747,6 +3748,24 @@ TypeSystemClang::GetCXXClassName(const CompilerType &type) {
return std::string(cxx_record_decl->getIdentifier()->getNameStart());
}
+bool TypeSystemClang::IsClassTypeForLanguage(lldb::opaque_compiler_type_t type,
+ lldb::LanguageType language) {
+ CompilerType ct(GetType(GetCanonicalQualType(type)));
+ if (!ct)
+ return false;
+
+ if (language == lldb::eLanguageTypeObjC)
+ return IsObjCClassType(ct);
+
+ if (language == lldb::eLanguageTypeObjC_plus_plus)
+ return IsObjCClassType(ct) || IsCXXClassType(ct);
+
+ if (Language::LanguageIsCPlusPlus(language))
+ return IsCXXClassType(ct);
+
+ return false;
+}
+
bool TypeSystemClang::IsCXXClassType(const CompilerType &type) {
if (!type)
return false;
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 709f89590ba3b..7a6123b1737a4 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -649,6 +649,9 @@ class TypeSystemClang : public TypeSystem {
static bool IsCXXClassType(const CompilerType &type);
+ bool IsClassTypeForLanguage(lldb::opaque_compiler_type_t type,
+ lldb::LanguageType language) override;
+
bool IsDefined(lldb::opaque_compiler_type_t type) override;
bool IsFloatingPointType(lldb::opaque_compiler_type_t type, uint32_t &count,
diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp
index 62c0ddf51c012..0e3f9229bfd6a 100644
--- a/lldb/source/Symbol/CompilerType.cpp
+++ b/lldb/source/Symbol/CompilerType.cpp
@@ -318,6 +318,13 @@ bool CompilerType::IsArrayOfScalarType() const {
return false;
}
+bool CompilerType::IsClassTypeForLanguage(lldb::LanguageType language) const {
+ if (IsValid())
+ if (auto type_system_sp = GetTypeSystem())
+ return type_system_sp->IsClassTypeForLanguage(m_type, language);
+ return false;
+}
+
bool CompilerType::IsBeingDefined() const {
if (IsValid())
if (auto type_system_sp = GetTypeSystem())
diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp
index 38b9f77e6ddda..8a6f0d8df325e 100644
--- a/lldb/source/ValueObject/ValueObject.cpp
+++ b/lldb/source/ValueObject/ValueObject.cpp
@@ -2816,6 +2816,8 @@ ValueObjectSP ValueObject::Dereference(Status &error) {
// FIXME(#59012): C++ stdlib formatters break with incomplete types (e.g.
// `std::vector<int> &`). Remove ObjC restriction once that's resolved.
if (Language::LanguageIsObjC(GetPreferredDisplayLanguage()) &&
+ !compiler_type.GetPointeeType().IsClassTypeForLanguage(
+ lldb::eLanguageTypeC_plus_plus) &&
HasSyntheticValue()) {
deref_compiler_type = compiler_type.GetPointeeType();
diff --git a/lldb/test/Shell/Expr/TestPrintCXXTypeAsObjCXX.test b/lldb/test/Shell/Expr/TestPrintCXXTypeAsObjCXX.test
new file mode 100644
index 0000000000000..f304d94902b0b
--- /dev/null
+++ b/lldb/test/Shell/Expr/TestPrintCXXTypeAsObjCXX.test
@@ -0,0 +1,34 @@
+# UNSUPPORTED: system-windows
+#
+# Tests that we don't crash when trying to `po` an incomplete
+# C++ type with synthetic children in an ObjC++ target.
+#
+# RUN: split-file %s %t
+# RUN: %clang_host -x objective-c++ -g %t/main.mm -o %t.out
+# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \
+# RUN: | FileCheck %s
+
+#--- main.mm
+
+#include <vector>
+
+int main() {
+ std::vector<int> * vec;
+ __builtin_debugtrap();
+}
+
+#--- commands.input
+
+run
+
+frame variable -O -- vec
+# CHECK: frame variable
+# CHECK-NEXT: warning: no object description available
+
+expression -O -- vec
+# CHECK: expression
+# CHECK-NEXT: size=error: incomplete type
+
+dwim-print -O -- vec
+# CHECK: dwim-print
+# CHECK-NEXT: size=error: incomplete type
``````````
</details>
https://github.com/llvm/llvm-project/pull/153454
More information about the lldb-commits
mailing list