Skip to content

[Cherry-pick into stable/20230725] [libDebugInfo] Prevent infinite recursion in DWARFDie::getTypeSize() (#74681) #7864

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 23 additions & 11 deletions llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "llvm/DebugInfo/DWARF/DWARFDie.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Dwarf.h"
Expand Down Expand Up @@ -487,18 +488,23 @@ void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
CallDiscriminator = toUnsigned(find(DW_AT_GNU_discriminator), 0);
}

std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) {
if (auto SizeAttr = find(DW_AT_byte_size))
static std::optional<uint64_t>
getTypeSizeImpl(DWARFDie Die, uint64_t PointerSize,
SmallPtrSetImpl<const DWARFDebugInfoEntry *> &Visited) {
// Cycle detected?
if (!Visited.insert(Die.getDebugInfoEntry()).second)
return {};
if (auto SizeAttr = Die.find(DW_AT_byte_size))
if (std::optional<uint64_t> Size = SizeAttr->getAsUnsignedConstant())
return Size;

switch (getTag()) {
switch (Die.getTag()) {
case DW_TAG_pointer_type:
case DW_TAG_reference_type:
case DW_TAG_rvalue_reference_type:
return PointerSize;
case DW_TAG_ptr_to_member_type: {
if (DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type))
if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type))
if (BaseType.getTag() == DW_TAG_subroutine_type)
return 2 * PointerSize;
return PointerSize;
Expand All @@ -508,19 +514,20 @@ std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) {
case DW_TAG_volatile_type:
case DW_TAG_restrict_type:
case DW_TAG_typedef: {
if (DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type))
return BaseType.getTypeSize(PointerSize);
if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type))
return getTypeSizeImpl(BaseType, PointerSize, Visited);
break;
}
case DW_TAG_array_type: {
DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type);
DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type);
if (!BaseType)
return std::nullopt;
std::optional<uint64_t> BaseSize = BaseType.getTypeSize(PointerSize);
std::optional<uint64_t> BaseSize =
getTypeSizeImpl(BaseType, PointerSize, Visited);
if (!BaseSize)
return std::nullopt;
uint64_t Size = *BaseSize;
for (DWARFDie Child : *this) {
for (DWARFDie Child : Die) {
if (Child.getTag() != DW_TAG_subrange_type)
continue;

Expand All @@ -540,13 +547,18 @@ std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) {
return Size;
}
default:
if (DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type))
return BaseType.getTypeSize(PointerSize);
if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type))
return getTypeSizeImpl(BaseType, PointerSize, Visited);
break;
}
return std::nullopt;
}

std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) {
SmallPtrSet<const DWARFDebugInfoEntry *, 4> Visited;
return getTypeSizeImpl(*this, PointerSize, Visited);
}

/// Helper to dump a DIE with all of its parents, but no siblings.
static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent,
DIDumpOptions DumpOpts, unsigned Depth = 0) {
Expand Down
36 changes: 36 additions & 0 deletions llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1660,6 +1660,42 @@ TEST(DWARFDebugInfo, TestFindRecurse) {
EXPECT_EQ(AbsDieName, StringOpt.value_or(nullptr));
}

TEST(DWARFDebugInfo, TestSelfRecursiveType) {
typedef uint32_t AddrType;
Triple Triple = getDefaultTargetTripleForAddrSize(sizeof(AddrType));
if (!isConfigurationSupported(Triple))
GTEST_SKIP();

auto ExpectedDG = dwarfgen::Generator::create(Triple, 4);
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
dwarfgen::DIE CUDie = CU.getUnitDIE();

// Create an invalid self-recursive typedef.
dwarfgen::DIE TypedefDie = CUDie.addChild(DW_TAG_typedef);
TypedefDie.addAttribute(DW_AT_name, DW_FORM_strp, "illegal");
TypedefDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, TypedefDie);

MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);

// Verify the number of compile units is correct.
uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
DWARFCompileUnit *U = cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
{
DWARFDie CUDie = U->getUnitDIE(false);
EXPECT_TRUE(CUDie.isValid());
DWARFDie TypedefDie = CUDie.getFirstChild();

// Test that getTypeSize doesn't get into an infinite loop.
EXPECT_EQ(TypedefDie.getTypeSize(sizeof(AddrType)), std::nullopt);
}
}

TEST(DWARFDebugInfo, TestDwarfToFunctions) {
// Test all of the dwarf::toXXX functions that take a
// std::optional<DWARFFormValue> and extract the values from it.
Expand Down