Skip to content

Commit 3cfdc05

Browse files
JDevlieghereAnthony Tran
authored andcommitted
[lldb] Defend against infinite recursion in GetClassDescriptor (llvm#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
1 parent 0ec1298 commit 3cfdc05

File tree

2 files changed

+20
-6
lines changed

2 files changed

+20
-6
lines changed

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,15 +1505,24 @@ AppleObjCRuntimeV2::GetClassDescriptorFromISA(ObjCISA isa) {
15051505

15061506
ObjCLanguageRuntime::ClassDescriptorSP
15071507
AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) {
1508+
ValueObjectSet seen;
1509+
return GetClassDescriptorImpl(valobj, seen);
1510+
}
1511+
1512+
ObjCLanguageRuntime::ClassDescriptorSP
1513+
AppleObjCRuntimeV2::GetClassDescriptorImpl(ValueObject &valobj,
1514+
ValueObjectSet &seen) {
1515+
seen.insert(&valobj);
1516+
15081517
ClassDescriptorSP objc_class_sp;
15091518
if (valobj.IsBaseClass()) {
15101519
ValueObject *parent = valobj.GetParent();
1511-
// if I am my own parent, bail out of here fast..
1512-
if (parent && parent != &valobj) {
1513-
ClassDescriptorSP parent_descriptor_sp = GetClassDescriptor(*parent);
1514-
if (parent_descriptor_sp)
1515-
return parent_descriptor_sp->GetSuperclass();
1516-
}
1520+
// Fail if there's a cycle in our parent chain.
1521+
if (!parent || seen.count(parent))
1522+
return nullptr;
1523+
if (ClassDescriptorSP parent_descriptor_sp =
1524+
GetClassDescriptorImpl(*parent, seen))
1525+
return parent_descriptor_sp->GetSuperclass();
15171526
return nullptr;
15181527
}
15191528
// if we get an invalid VO (which might still happen when playing around with

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
2121

2222
#include "llvm/ADT/BitVector.h"
23+
#include "llvm/ADT/SmallSet.h"
2324

2425
class RemoteNXMapTable;
2526

@@ -421,6 +422,10 @@ class AppleObjCRuntimeV2 : public AppleObjCRuntime {
421422

422423
lldb::addr_t GetISAHashTablePointer();
423424

425+
using ValueObjectSet = llvm::SmallPtrSet<ValueObject *, 8>;
426+
ClassDescriptorSP GetClassDescriptorImpl(ValueObject &valobj,
427+
ValueObjectSet &seen);
428+
424429
/// Update the generation count of realized classes. This is not an exact
425430
/// count but rather a value that is incremented when new classes are realized
426431
/// or destroyed. Unlike the count in gdb_objc_realized_classes, it will

0 commit comments

Comments
 (0)