https://github.com/royitaqi updated 
https://github.com/llvm/llvm-project/pull/196448

>From b0171e9428db3628823a1de6bbb657f99df32075 Mon Sep 17 00:00:00 2001
From: Roy Shi <[email protected]>
Date: Thu, 7 May 2026 16:36:21 -0700
Subject: [PATCH 1/6] Add a test to repro the problem

---
 llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp | 156 +++++++++++++++++++++
 1 file changed, 156 insertions(+)

diff --git a/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp 
b/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp
index 299e19e3c896e..b7abdd94ce645 100644
--- a/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp
+++ b/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp
@@ -9,6 +9,7 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"
 #include "llvm/DebugInfo/GSYM/DwarfTransformer.h"
 #include "llvm/DebugInfo/GSYM/ExtractRanges.h"
 #include "llvm/DebugInfo/GSYM/FileEntry.h"
@@ -5687,3 +5688,158 @@ TEST(GSYMTest, TestMergedFunctionsInfoLargeOffsets) {
   EXPECT_EQ(DecResult->MergedFunctions[0].Name, LargeName1);
   EXPECT_EQ(DecResult->MergedFunctions[1].Name, LargeName2);
 }
+
+TEST(GSYMTest, TestDWARFTypedefCycleDoesNotCrash) {
+  // Test that a self-referencing typedef cycle in DWARF does not cause
+  // infinite recursion in DWARFTypePrinter::unwrapReferencedTypedefType().
+  // This can happen when dsymutil's classic linker incorrectly deduplicates
+  // typedefs with the same name but different underlying types (e.g. from
+  // preferred_name), creating a typedef that points to itself.
+  //
+  // The crash path: DWARFTypePrinter::appendUnqualifiedNameBefore sees a
+  // DW_AT_name with the _STN| prefix (simplified template name), calls
+  // appendTemplateParameters, which for each DW_TAG_template_type_parameter
+  // calls unwrapReferencedTypedefType. With a cyclic typedef, this recurses
+  // infinitely.
+  //
+  // debug_info layout (DWARF32, AddrSize=8):
+  //   0x00: unit_length (4 bytes)
+  //   0x04: version=4 (2), abbrev_offset (4), addr_size=8 (1) = 7 bytes
+  //   0x0B: CU DIE (abbrev 1): strp(4) + addr(8) + addr(8) + data2(2) = 23
+  //   0x22: Subprogram DIE (abbrev 2): strp(4) + addr(8) + addr(8) = 21
+  //   0x37: Template param DIE (abbrev 3): strp(4) + ref4(4) = 9
+  //   0x40: null terminator (1 byte, end of subprogram children)
+  //   0x41: Typedef DIE (abbrev 4): strp(4) + ref4(4) = 9
+  //   0x4A: null terminator (1 byte, end of CU children)
+  //
+  // Template param's DW_AT_type -> 0x41 (typedef)
+  // Typedef's DW_AT_type -> 0x41 (self-referencing cycle)
+
+  // String table: "" (0x00), "/tmp/main.cpp" (0x01), "_STN|foo|<MyType>"
+  // (0x0F), "T" (0x21), "MyType" (0x23)
+  StringRef yamldata = R"(
+  debug_str:
+    - ''
+    - /tmp/main.cpp
+    - '_STN|foo|<MyType>'
+    - T
+    - MyType
+  debug_abbrev:
+    - Table:
+        - Code:            0x00000001
+          Tag:             DW_TAG_compile_unit
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_low_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_high_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_language
+              Form:            DW_FORM_data2
+        - Code:            0x00000002
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_low_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_high_pc
+              Form:            DW_FORM_addr
+        - Code:            0x00000003
+          Tag:             DW_TAG_template_type_parameter
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+        - Code:            0x00000004
+          Tag:             DW_TAG_typedef
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+  debug_info:
+    - Version:         4
+      AddrSize:        8
+      Entries:
+        - AbbrCode:        0x00000001
+          Values:
+            - Value:           0x0000000000000001
+            - Value:           0x0000000000001000
+            - Value:           0x0000000000002000
+            - Value:           0x0000000000000004
+        - AbbrCode:        0x00000002
+          Values:
+            - Value:           0x000000000000000F
+            - Value:           0x0000000000001000
+            - Value:           0x0000000000002000
+        - AbbrCode:        0x00000003
+          Values:
+            - Value:           0x0000000000000021
+            - Value:           0x0000000000000041
+        - AbbrCode:        0x00000000
+        - AbbrCode:        0x00000004
+          Values:
+            - Value:           0x0000000000000023
+            - Value:           0x0000000000000041
+        - AbbrCode:        0x00000000
+  )";
+  auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata);
+  ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded());
+  std::unique_ptr<DWARFContext> DwarfContext =
+      DWARFContext::create(*ErrOrSections, 8);
+  ASSERT_TRUE(DwarfContext.get() != nullptr);
+
+  // Verify the typedef DIE is at offset 0x41 and self-references.
+  auto &CUDie = *DwarfContext->compile_units().begin();
+  DWARFDie CURoot = CUDie->getUnitDIE(false);
+  ASSERT_TRUE(CURoot.isValid());
+  // Walk children to find the typedef and verify the cycle.
+  bool FoundTypedef = false;
+  for (DWARFDie Child : CURoot.children()) {
+    if (Child.getTag() == dwarf::DW_TAG_typedef) {
+      EXPECT_EQ(Child.getOffset(), 0x41u);
+      auto TypeAttr = Child.find(dwarf::DW_AT_type);
+      ASSERT_TRUE(TypeAttr.has_value());
+      auto RefDie = Child.getAttributeValueAsReferencedDie(*TypeAttr);
+      EXPECT_EQ(RefDie.getOffset(), Child.getOffset());
+      FoundTypedef = true;
+    }
+  }
+  ASSERT_TRUE(FoundTypedef);
+
+  // Exercise DWARFTypePrinter on the subprogram with the _STN| name.
+  // appendUnqualifiedName -> appendTemplateParameters ->
+  // unwrapReferencedTypedefType must not infinitely recurse.
+  for (DWARFDie Child : CURoot.children()) {
+    if (Child.getTag() == dwarf::DW_TAG_subprogram) {
+      std::string Result;
+      raw_string_ostream StrOS(Result);
+      DWARFTypePrinter<DWARFDie>(StrOS).appendUnqualifiedName(Child);
+      EXPECT_FALSE(Result.empty());
+    }
+  }
+
+  // Also verify DwarfTransformer::convert() succeeds.
+  auto &OS = llvm::nulls();
+  OutputAggregator OSAgg(&OS);
+  GsymCreatorV1 GC;
+  DwarfTransformer DT(*DwarfContext, GC);
+  ASSERT_THAT_ERROR(DT.convert(1, OSAgg), Succeeded());
+  ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
+  SmallString<512> Str;
+  raw_svector_ostream OutStrm(Str);
+  FileWriter FW(OutStrm, llvm::endianness::native);
+  FW.setStringOffsetSize(GC.getStringOffsetSize());
+  ASSERT_THAT_ERROR(GC.encode(FW), Succeeded());
+  auto GROrErr = GsymReader::copyBuffer(OutStrm.str());
+  ASSERT_THAT_EXPECTED(GROrErr, Succeeded());
+  const std::unique_ptr<GsymReader> &GR = *GROrErr;
+  EXPECT_EQ(GR->getNumAddresses(), 1u);
+}

>From 764b1e4f0fd7cc21fa2a17e309cabdaf4439108e Mon Sep 17 00:00:00 2001
From: Roy Shi <[email protected]>
Date: Thu, 7 May 2026 16:36:33 -0700
Subject: [PATCH 2/6] Fix the problem

---
 .../include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h 
b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
index 9986aaabf6ed4..ccb823f95b74a 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
@@ -147,6 +147,8 @@ void DWARFTypePrinter<DieType>::appendArrayType(const 
DieType &D) {
   EndedWithTemplate = false;
 }
 
+constexpr unsigned kMaxTypedefUnwrapDepth = 256;
+
 namespace detail {
 template <typename DieType>
 DieType resolveReferencedType(DieType D,
@@ -169,8 +171,11 @@ const char *toString(std::optional<DWARFFormValueType> F) {
 }
 
 /// Resolve the DW_AT_type of \c D until we reach a DIE that is not a
-/// DW_TAG_typedef.
-template <typename DieType> DieType unwrapReferencedTypedefType(DieType D) {
+/// DW_TAG_typedef. Gives up after 256 typedefs to guard against cycles in
+/// malformed DWARF.
+template <typename DieType>
+DieType unwrapReferencedTypedefType(DieType D,
+                                    unsigned Depth = kMaxTypedefUnwrapDepth) {
   auto TypeAttr = D.find(dwarf::DW_AT_type);
   if (!TypeAttr)
     return DieType();
@@ -179,8 +184,8 @@ template <typename DieType> DieType 
unwrapReferencedTypedefType(DieType D) {
   if (!Unwrapped)
     return DieType();
 
-  if (Unwrapped.getTag() == dwarf::DW_TAG_typedef)
-    return unwrapReferencedTypedefType(Unwrapped);
+  if (Unwrapped.getTag() == dwarf::DW_TAG_typedef && Depth > 0)
+    return unwrapReferencedTypedefType(Unwrapped, Depth - 1);
 
   return Unwrapped;
 }

>From bae699aba48cad7e46b502c5374b7703177be755 Mon Sep 17 00:00:00 2001
From: Roy Shi <[email protected]>
Date: Thu, 7 May 2026 17:07:34 -0700
Subject: [PATCH 3/6] Inline the magic number

---
 llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h 
b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
index ccb823f95b74a..0310ffc894e27 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
@@ -147,8 +147,6 @@ void DWARFTypePrinter<DieType>::appendArrayType(const 
DieType &D) {
   EndedWithTemplate = false;
 }
 
-constexpr unsigned kMaxTypedefUnwrapDepth = 256;
-
 namespace detail {
 template <typename DieType>
 DieType resolveReferencedType(DieType D,
@@ -174,8 +172,7 @@ const char *toString(std::optional<DWARFFormValueType> F) {
 /// DW_TAG_typedef. Gives up after 256 typedefs to guard against cycles in
 /// malformed DWARF.
 template <typename DieType>
-DieType unwrapReferencedTypedefType(DieType D,
-                                    unsigned Depth = kMaxTypedefUnwrapDepth) {
+DieType unwrapReferencedTypedefType(DieType D, unsigned Depth = 256) {
   auto TypeAttr = D.find(dwarf::DW_AT_type);
   if (!TypeAttr)
     return DieType();

>From 3fce4a2f81426c32b1cf8f8c4de2550b9df216ec Mon Sep 17 00:00:00 2001
From: Roy Shi <[email protected]>
Date: Fri, 8 May 2026 12:14:55 -0700
Subject: [PATCH 4/6] Convert to loop; use DenseSet

---
 .../llvm/DebugInfo/DWARF/DWARFTypePrinter.h   | 29 ++++++++++---------
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h 
b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
index 0310ffc894e27..4d97ac93eea1b 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H
 #define LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H
 
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/BinaryFormat/Dwarf.h"
@@ -169,22 +170,24 @@ const char *toString(std::optional<DWARFFormValueType> F) 
{
 }
 
 /// Resolve the DW_AT_type of \c D until we reach a DIE that is not a
-/// DW_TAG_typedef. Gives up after 256 typedefs to guard against cycles in
-/// malformed DWARF.
-template <typename DieType>
-DieType unwrapReferencedTypedefType(DieType D, unsigned Depth = 256) {
-  auto TypeAttr = D.find(dwarf::DW_AT_type);
-  if (!TypeAttr)
-    return DieType();
+/// DW_TAG_typedef. Gives up if a cycle is detected in malformed DWARF.
+/// In this case, return the last typedef DIE before the cycle is formed.
+template <typename DieType> DieType unwrapReferencedTypedefType(DieType D) {
+  SmallSet<uint64_t, 4> Visited;
+  while (true) {
+    auto TypeAttr = D.find(dwarf::DW_AT_type);
+    if (!TypeAttr)
+      return DieType();
 
-  auto Unwrapped = detail::resolveReferencedType(D, *TypeAttr);
-  if (!Unwrapped)
-    return DieType();
+    auto Unwrapped = detail::resolveReferencedType(D, *TypeAttr);
+    if (!Unwrapped || Unwrapped.getTag() != dwarf::DW_TAG_typedef)
+      return Unwrapped;
 
-  if (Unwrapped.getTag() == dwarf::DW_TAG_typedef && Depth > 0)
-    return unwrapReferencedTypedefType(Unwrapped, Depth - 1);
+    if (!Visited.insert(Unwrapped.getOffset()).second)
+      return D;
 
-  return Unwrapped;
+    D = Unwrapped;
+  }
 }
 } // namespace detail
 

>From dfd225752832e5b498b7105c8ce6c0a33f3abbc9 Mon Sep 17 00:00:00 2001
From: Roy Shi <[email protected]>
Date: Fri, 8 May 2026 12:21:37 -0700
Subject: [PATCH 5/6] Instead, return the DIE where the cycle is formed

---
 llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h 
b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
index 4d97ac93eea1b..6c46d7cde77ef 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
@@ -171,7 +171,7 @@ const char *toString(std::optional<DWARFFormValueType> F) {
 
 /// Resolve the DW_AT_type of \c D until we reach a DIE that is not a
 /// DW_TAG_typedef. Gives up if a cycle is detected in malformed DWARF.
-/// In this case, return the last typedef DIE before the cycle is formed.
+/// In this case, returns the typedef DIE where the cycle is formed.
 template <typename DieType> DieType unwrapReferencedTypedefType(DieType D) {
   SmallSet<uint64_t, 4> Visited;
   while (true) {
@@ -184,7 +184,7 @@ template <typename DieType> DieType 
unwrapReferencedTypedefType(DieType D) {
       return Unwrapped;
 
     if (!Visited.insert(Unwrapped.getOffset()).second)
-      return D;
+      return Unwrapped;
 
     D = Unwrapped;
   }

>From eaf2082ce64dc0676d6f519acc5c7937187fb168 Mon Sep 17 00:00:00 2001
From: Roy Shi <[email protected]>
Date: Fri, 8 May 2026 12:52:34 -0700
Subject: [PATCH 6/6] Fix build error in lldb

---
 lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h
index d92de658a49e8..9736b80ac375f 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h
@@ -123,6 +123,8 @@ class DWARFBaseDIE {
   // LLVM libraries.
   dw_tag_t getTag() const { return Tag(); }
 
+  dw_offset_t getOffset() const { return GetOffset(); }
+
   const char *getShortName() const { return GetName(); }
 
 protected:

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to