[Lldb-commits] [lldb] [lldb] Defend against infinite recursion in GetClassDescriptor (PR #145396)
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Mon Jun 23 12:46:49 PDT 2025
https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/145396
We defend against a direct cycle where a base class ValueObject is its own parent, but not against a longer base cycle. This cycle requires that some value's Type includes a base class, and that base class is in a class hierarchy that cycles back to the original base class.
I wrote a test case that creates a cycle in the class hierarchy by dynamically overwriting the superclass of an object, but I can't reproduce the crash. I can't think of any other way to make a real object that behaves that way. Maybe is a type system problem in making up the type for whatever type we're trying to ingest here.
While unsatisfying, without a reproducer this is the best we can do for now.
rdar://140293233
>From 1da01acdb21fd7d7a58de8d19175479394f727d2 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Mon, 23 Jun 2025 14:26:03 -0500
Subject: [PATCH] [lldb] Defend against infinite recursion in
GetClassDescriptor
We defend against a direct cycle where a base class ValueObject is its
own parent, but not against a longer base cycle. This cycle requires
that some value's Type includes a base class, and that base class is in
a class hierarchy that cycles back to the original base class.
I wrote a test case that creates a cycle in the class hierarchy by
dynamically overwriting the superclass of an object, but I can't
reproduce the crash. I can't think of any other way to make a real
object that behaves that way. Maybe is a type system problem in making
up the type for whatever type we're trying to ingest here.
While unsatisfying, without a reproducer this is the best we can do for
now.
rdar://140293233
---
.../AppleObjCRuntime/AppleObjCRuntimeV2.cpp | 21 +++++++++++++------
.../AppleObjCRuntime/AppleObjCRuntimeV2.h | 5 +++++
2 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index e459cb281793a..4fcdebe5bac62 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -1505,15 +1505,24 @@ AppleObjCRuntimeV2::GetClassDescriptorFromISA(ObjCISA isa) {
ObjCLanguageRuntime::ClassDescriptorSP
AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) {
+ ValueObjectSet seen;
+ return GetClassDescriptorImpl(valobj, seen);
+}
+
+ObjCLanguageRuntime::ClassDescriptorSP
+AppleObjCRuntimeV2::GetClassDescriptorImpl(ValueObject &valobj,
+ ValueObjectSet &seen) {
+ seen.insert(&valobj);
+
ClassDescriptorSP objc_class_sp;
if (valobj.IsBaseClass()) {
ValueObject *parent = valobj.GetParent();
- // if I am my own parent, bail out of here fast..
- if (parent && parent != &valobj) {
- ClassDescriptorSP parent_descriptor_sp = GetClassDescriptor(*parent);
- if (parent_descriptor_sp)
- return parent_descriptor_sp->GetSuperclass();
- }
+ // Fail if there's a cycle in our parent chain.
+ if (!parent || seen.count(parent))
+ return nullptr;
+ if (ClassDescriptorSP parent_descriptor_sp =
+ GetClassDescriptorImpl(*parent, seen))
+ return parent_descriptor_sp->GetSuperclass();
return nullptr;
}
// if we get an invalid VO (which might still happen when playing around with
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
index 79840f9be79b3..e5dba5bddf936 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
@@ -20,6 +20,7 @@
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/SmallSet.h"
class RemoteNXMapTable;
@@ -421,6 +422,10 @@ class AppleObjCRuntimeV2 : public AppleObjCRuntime {
lldb::addr_t GetISAHashTablePointer();
+ using ValueObjectSet = llvm::SmallSet<ValueObject *, 8>;
+ ClassDescriptorSP GetClassDescriptorImpl(ValueObject &valobj,
+ ValueObjectSet &seen);
+
/// Update the generation count of realized classes. This is not an exact
/// count but rather a value that is incremented when new classes are realized
/// or destroyed. Unlike the count in gdb_objc_realized_classes, it will
More information about the lldb-commits
mailing list