Skip to content

Commit c6805ea

Browse files
[libDebugInfo] Prevent infinite recursion in DWARFDie::getTypeSize() (llvm#74681)
when run on invalid input.
1 parent 93509b4 commit c6805ea

File tree

2 files changed

+59
-11
lines changed

2 files changed

+59
-11
lines changed

llvm/lib/DebugInfo/DWARF/DWARFDie.cpp

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
10+
#include "llvm/ADT/SmallPtrSet.h"
1011
#include "llvm/ADT/SmallSet.h"
1112
#include "llvm/ADT/StringRef.h"
1213
#include "llvm/BinaryFormat/Dwarf.h"
@@ -489,18 +490,23 @@ void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
489490
CallDiscriminator = toUnsigned(find(DW_AT_GNU_discriminator), 0);
490491
}
491492

492-
std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) {
493-
if (auto SizeAttr = find(DW_AT_byte_size))
493+
static std::optional<uint64_t>
494+
getTypeSizeImpl(DWARFDie Die, uint64_t PointerSize,
495+
SmallPtrSetImpl<const DWARFDebugInfoEntry *> &Visited) {
496+
// Cycle detected?
497+
if (!Visited.insert(Die.getDebugInfoEntry()).second)
498+
return {};
499+
if (auto SizeAttr = Die.find(DW_AT_byte_size))
494500
if (std::optional<uint64_t> Size = SizeAttr->getAsUnsignedConstant())
495501
return Size;
496502

497-
switch (getTag()) {
503+
switch (Die.getTag()) {
498504
case DW_TAG_pointer_type:
499505
case DW_TAG_reference_type:
500506
case DW_TAG_rvalue_reference_type:
501507
return PointerSize;
502508
case DW_TAG_ptr_to_member_type: {
503-
if (DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type))
509+
if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type))
504510
if (BaseType.getTag() == DW_TAG_subroutine_type)
505511
return 2 * PointerSize;
506512
return PointerSize;
@@ -510,19 +516,20 @@ std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) {
510516
case DW_TAG_volatile_type:
511517
case DW_TAG_restrict_type:
512518
case DW_TAG_typedef: {
513-
if (DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type))
514-
return BaseType.getTypeSize(PointerSize);
519+
if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type))
520+
return getTypeSizeImpl(BaseType, PointerSize, Visited);
515521
break;
516522
}
517523
case DW_TAG_array_type: {
518-
DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type);
524+
DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type);
519525
if (!BaseType)
520526
return std::nullopt;
521-
std::optional<uint64_t> BaseSize = BaseType.getTypeSize(PointerSize);
527+
std::optional<uint64_t> BaseSize =
528+
getTypeSizeImpl(BaseType, PointerSize, Visited);
522529
if (!BaseSize)
523530
return std::nullopt;
524531
uint64_t Size = *BaseSize;
525-
for (DWARFDie Child : *this) {
532+
for (DWARFDie Child : Die) {
526533
if (Child.getTag() != DW_TAG_subrange_type)
527534
continue;
528535

@@ -542,13 +549,18 @@ std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) {
542549
return Size;
543550
}
544551
default:
545-
if (DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type))
546-
return BaseType.getTypeSize(PointerSize);
552+
if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type))
553+
return getTypeSizeImpl(BaseType, PointerSize, Visited);
547554
break;
548555
}
549556
return std::nullopt;
550557
}
551558

559+
std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) {
560+
SmallPtrSet<const DWARFDebugInfoEntry *, 4> Visited;
561+
return getTypeSizeImpl(*this, PointerSize, Visited);
562+
}
563+
552564
/// Helper to dump a DIE with all of its parents, but no siblings.
553565
static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent,
554566
DIDumpOptions DumpOpts, unsigned Depth = 0) {

llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1615,6 +1615,42 @@ TEST(DWARFDebugInfo, TestFindRecurse) {
16151615
EXPECT_EQ(AbsDieName, StringOpt.value_or(nullptr));
16161616
}
16171617

1618+
TEST(DWARFDebugInfo, TestSelfRecursiveType) {
1619+
typedef uint32_t AddrType;
1620+
Triple Triple = getDefaultTargetTripleForAddrSize(sizeof(AddrType));
1621+
if (!isConfigurationSupported(Triple))
1622+
GTEST_SKIP();
1623+
1624+
auto ExpectedDG = dwarfgen::Generator::create(Triple, 4);
1625+
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
1626+
dwarfgen::Generator *DG = ExpectedDG.get().get();
1627+
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
1628+
dwarfgen::DIE CUDie = CU.getUnitDIE();
1629+
1630+
// Create an invalid self-recursive typedef.
1631+
dwarfgen::DIE TypedefDie = CUDie.addChild(DW_TAG_typedef);
1632+
TypedefDie.addAttribute(DW_AT_name, DW_FORM_strp, "illegal");
1633+
TypedefDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, TypedefDie);
1634+
1635+
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
1636+
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
1637+
EXPECT_TRUE((bool)Obj);
1638+
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
1639+
1640+
// Verify the number of compile units is correct.
1641+
uint32_t NumCUs = DwarfContext->getNumCompileUnits();
1642+
EXPECT_EQ(NumCUs, 1u);
1643+
DWARFCompileUnit *U = cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
1644+
{
1645+
DWARFDie CUDie = U->getUnitDIE(false);
1646+
EXPECT_TRUE(CUDie.isValid());
1647+
DWARFDie TypedefDie = CUDie.getFirstChild();
1648+
1649+
// Test that getTypeSize doesn't get into an infinite loop.
1650+
EXPECT_EQ(TypedefDie.getTypeSize(sizeof(AddrType)), std::nullopt);
1651+
}
1652+
}
1653+
16181654
TEST(DWARFDebugInfo, TestDwarfToFunctions) {
16191655
// Test all of the dwarf::toXXX functions that take a
16201656
// std::optional<DWARFFormValue> and extract the values from it.

0 commit comments

Comments
 (0)