Skip to content

Commit 63204a9

Browse files
Merge pull request #7864 from adrian-prantl/cherry-pick-stable-20230725-libDebugInfo-Prevent-infinite-recursion-in-DWARFDie-getTypeSize-74681
[Cherry-pick into stable/20230725] [libDebugInfo] Prevent infinite recursion in DWARFDie::getTypeSize() (llvm#74681)
2 parents 572a5a4 + bf9b995 commit 63204a9

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"
@@ -487,18 +488,23 @@ void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
487488
CallDiscriminator = toUnsigned(find(DW_AT_GNU_discriminator), 0);
488489
}
489490

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

495-
switch (getTag()) {
501+
switch (Die.getTag()) {
496502
case DW_TAG_pointer_type:
497503
case DW_TAG_reference_type:
498504
case DW_TAG_rvalue_reference_type:
499505
return PointerSize;
500506
case DW_TAG_ptr_to_member_type: {
501-
if (DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type))
507+
if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type))
502508
if (BaseType.getTag() == DW_TAG_subroutine_type)
503509
return 2 * PointerSize;
504510
return PointerSize;
@@ -508,19 +514,20 @@ std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) {
508514
case DW_TAG_volatile_type:
509515
case DW_TAG_restrict_type:
510516
case DW_TAG_typedef: {
511-
if (DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type))
512-
return BaseType.getTypeSize(PointerSize);
517+
if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type))
518+
return getTypeSizeImpl(BaseType, PointerSize, Visited);
513519
break;
514520
}
515521
case DW_TAG_array_type: {
516-
DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type);
522+
DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type);
517523
if (!BaseType)
518524
return std::nullopt;
519-
std::optional<uint64_t> BaseSize = BaseType.getTypeSize(PointerSize);
525+
std::optional<uint64_t> BaseSize =
526+
getTypeSizeImpl(BaseType, PointerSize, Visited);
520527
if (!BaseSize)
521528
return std::nullopt;
522529
uint64_t Size = *BaseSize;
523-
for (DWARFDie Child : *this) {
530+
for (DWARFDie Child : Die) {
524531
if (Child.getTag() != DW_TAG_subrange_type)
525532
continue;
526533

@@ -540,13 +547,18 @@ std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) {
540547
return Size;
541548
}
542549
default:
543-
if (DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type))
544-
return BaseType.getTypeSize(PointerSize);
550+
if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type))
551+
return getTypeSizeImpl(BaseType, PointerSize, Visited);
545552
break;
546553
}
547554
return std::nullopt;
548555
}
549556

557+
std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) {
558+
SmallPtrSet<const DWARFDebugInfoEntry *, 4> Visited;
559+
return getTypeSizeImpl(*this, PointerSize, Visited);
560+
}
561+
550562
/// Helper to dump a DIE with all of its parents, but no siblings.
551563
static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent,
552564
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
@@ -1660,6 +1660,42 @@ TEST(DWARFDebugInfo, TestFindRecurse) {
16601660
EXPECT_EQ(AbsDieName, StringOpt.value_or(nullptr));
16611661
}
16621662

1663+
TEST(DWARFDebugInfo, TestSelfRecursiveType) {
1664+
typedef uint32_t AddrType;
1665+
Triple Triple = getDefaultTargetTripleForAddrSize(sizeof(AddrType));
1666+
if (!isConfigurationSupported(Triple))
1667+
GTEST_SKIP();
1668+
1669+
auto ExpectedDG = dwarfgen::Generator::create(Triple, 4);
1670+
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
1671+
dwarfgen::Generator *DG = ExpectedDG.get().get();
1672+
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
1673+
dwarfgen::DIE CUDie = CU.getUnitDIE();
1674+
1675+
// Create an invalid self-recursive typedef.
1676+
dwarfgen::DIE TypedefDie = CUDie.addChild(DW_TAG_typedef);
1677+
TypedefDie.addAttribute(DW_AT_name, DW_FORM_strp, "illegal");
1678+
TypedefDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, TypedefDie);
1679+
1680+
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
1681+
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
1682+
EXPECT_TRUE((bool)Obj);
1683+
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
1684+
1685+
// Verify the number of compile units is correct.
1686+
uint32_t NumCUs = DwarfContext->getNumCompileUnits();
1687+
EXPECT_EQ(NumCUs, 1u);
1688+
DWARFCompileUnit *U = cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
1689+
{
1690+
DWARFDie CUDie = U->getUnitDIE(false);
1691+
EXPECT_TRUE(CUDie.isValid());
1692+
DWARFDie TypedefDie = CUDie.getFirstChild();
1693+
1694+
// Test that getTypeSize doesn't get into an infinite loop.
1695+
EXPECT_EQ(TypedefDie.getTypeSize(sizeof(AddrType)), std::nullopt);
1696+
}
1697+
}
1698+
16631699
TEST(DWARFDebugInfo, TestDwarfToFunctions) {
16641700
// Test all of the dwarf::toXXX functions that take a
16651701
// std::optional<DWARFFormValue> and extract the values from it.

0 commit comments

Comments
 (0)