[llvm] [libDebugInfo] Prevent infinite recursion in DWARFDie::getTypeSize() (PR #74681)
Adrian Prantl via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 7 11:17:42 PST 2023
https://github.com/adrian-prantl updated https://github.com/llvm/llvm-project/pull/74681
>From 8474a8c387616ab08f6a69a65a68be36f776a94c Mon Sep 17 00:00:00 2001
From: Adrian Prantl <aprantl at apple.com>
Date: Wed, 6 Dec 2023 16:28:31 -0800
Subject: [PATCH] [libDebugInfo] Prevent infinite recursion in
DWARFDie::getTypeSize()
when run on invalid input.
---
llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 34 ++++++++++++------
.../DebugInfo/DWARF/DWARFDebugInfoTest.cpp | 36 +++++++++++++++++++
2 files changed, 59 insertions(+), 11 deletions(-)
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index 0f01933002c06d..66492f7bf80433 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -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"
@@ -489,18 +490,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;
@@ -510,19 +516,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;
@@ -542,13 +549,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) {
diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
index 0b7f8f41bc53f4..5cb0310c0ad097 100644
--- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
@@ -1615,6 +1615,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.
More information about the llvm-commits
mailing list