[llvm] [DebugInfo] Fix segfault in constructSubprogramScopeDIE with null subprogram type (PR #184299)

via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 3 00:52:08 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-debuginfo

Author: Shivam Kunwar (phyBrackets)

<details>
<summary>Changes</summary>

Guard against null DISubroutineType when checking for variadic parameters in `constructSubprogramScopeDIE`. `DISubprograms` may lack a type field when using LineTablesOnly emission, causing a null pointer dereference. 

Fixes #<!-- -->184003

---
Full diff: https://github.com/llvm/llvm-project/pull/184299.diff


2 Files Affected:

- (modified) llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp (+32-26) 
- (added) llvm/test/DebugInfo/X86/empty-struct-no-crash.ll (+28) 


``````````diff
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index eb55b47dfde2b..52d98ecc554a7 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -188,7 +188,7 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE(
 
   auto *CB = GVContext ? dyn_cast<DICommonBlock>(GVContext) : nullptr;
   DIE *ContextDIE = CB ? getOrCreateCommonBlock(CB, GlobalExprs)
-    : getOrCreateContextDIE(GVContext);
+                       : getOrCreateContextDIE(GVContext);
 
   // Add to map.
   DIE *VariableDIE = &createAndAddDIE(GV->getTag(), *ContextDIE, GV);
@@ -241,8 +241,9 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE(
   return VariableDIE;
 }
 
-void DwarfCompileUnit::addLocationAttribute(
-    DIE *VariableDIE, const DIGlobalVariable *GV, ArrayRef<GlobalExpr> GlobalExprs) {
+void DwarfCompileUnit::addLocationAttribute(DIE *VariableDIE,
+                                            const DIGlobalVariable *GV,
+                                            ArrayRef<GlobalExpr> GlobalExprs) {
   bool addToAccelTable = false;
   DIELoc *Loc = nullptr;
   std::optional<unsigned> NVPTXAddressSpace;
@@ -446,8 +447,7 @@ void DwarfCompileUnit::addRange(RangeSpan Range) {
   // emitted into and the subprogram was contained within. If these are the
   // same then extend our current range, otherwise add this as a new range.
   if (CURanges.empty() || !SameAsPrevCU ||
-      (&CURanges.back().End->getSection() !=
-       &Range.End->getSection())) {
+      (&CURanges.back().End->getSection() != &Range.End->getSection())) {
     // Before a new range is added, always terminate the prior line table.
     if (PrevCU)
       DD->terminateLineTable(PrevCU);
@@ -475,8 +475,8 @@ void DwarfCompileUnit::initStmtList() {
   // left in the skeleton CU and so not included.
   // The line table entries are not always emitted in assembly, so it
   // is not okay to use line_table_start here.
-      addSectionLabel(getUnitDie(), dwarf::DW_AT_stmt_list, LineTableStartSym,
-                      TLOF.getDwarfLineSection()->getBeginSymbol());
+  addSectionLabel(getUnitDie(), dwarf::DW_AT_stmt_list, LineTableStartSym,
+                  TLOF.getDwarfLineSection()->getBeginSymbol());
 }
 
 void DwarfCompileUnit::applyStmtList(DIE &D) {
@@ -602,7 +602,7 @@ DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP,
         DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
         DIExpressionCursor Cursor({});
         DwarfExpr.addWasmLocation(FrameBase.Location.WasmLoc.Kind,
-            FrameBase.Location.WasmLoc.Index);
+                                  FrameBase.Location.WasmLoc.Index);
         DwarfExpr.addExpression(std::move(Cursor));
         addBlock(*SPDie, dwarf::DW_AT_frame_base, DwarfExpr.finalize());
       }
@@ -1141,15 +1141,19 @@ DIE &DwarfCompileUnit::constructSubprogramScopeDIE(const DISubprogram *Sub,
   }
 
   // If this is a variadic function, add an unspecified parameter.
-  DITypeArray FnArgs = Sub->getType()->getTypeArray();
-
-  // If we have a single element of null, it is a function that returns void.
-  // If we have more than one elements and the last one is null, it is a
-  // variadic function.
-  if (FnArgs.size() > 1 && !FnArgs[FnArgs.size() - 1] &&
-      !includeMinimalInlineScopes())
-    ScopeDIE.addChild(
-        DIE::get(DIEValueAllocator, dwarf::DW_TAG_unspecified_parameters));
+  // Sub->getType() may be null when using LineTablesOnly emission, since
+  // DISubprograms are not required to have a type in that mode.
+  if (auto *SPTy = Sub->getType()) {
+    DITypeArray FnArgs = SPTy->getTypeArray();
+
+    // If we have a single element of null, it is a function that returns void.
+    // If we have more than one elements and the last one is null, it is a
+    // variadic function.
+    if (FnArgs.size() > 1 && !FnArgs[FnArgs.size() - 1] &&
+        !includeMinimalInlineScopes())
+      ScopeDIE.addChild(
+          DIE::get(DIEValueAllocator, dwarf::DW_TAG_unspecified_parameters));
+  }
 
   return ScopeDIE;
 }
@@ -1563,8 +1567,8 @@ void DwarfCompileUnit::createAbstractEntity(const DINode *Node,
                                            nullptr /* IA */);
     DU->addScopeVariable(Scope, cast<DbgVariable>(Entity.get()));
   } else if (isa<const DILabel>(Node)) {
-    Entity = std::make_unique<DbgLabel>(
-                        cast<const DILabel>(Node), nullptr /* IA */);
+    Entity =
+        std::make_unique<DbgLabel>(cast<const DILabel>(Node), nullptr /* IA */);
     DU->addScopeLabel(Scope, cast<DbgLabel>(Entity.get()));
   }
 }
@@ -1576,9 +1580,9 @@ void DwarfCompileUnit::emitHeader(bool UseOffsets) {
     Asm->OutStreamer->emitLabel(LabelBegin);
   }
 
-  dwarf::UnitType UT = Skeleton ? dwarf::DW_UT_split_compile
-                                : DD->useSplitDwarf() ? dwarf::DW_UT_skeleton
-                                                      : dwarf::DW_UT_compile;
+  dwarf::UnitType UT = Skeleton              ? dwarf::DW_UT_split_compile
+                       : DD->useSplitDwarf() ? dwarf::DW_UT_skeleton
+                                             : dwarf::DW_UT_compile;
   DwarfUnit::emitCommonHeader(UseOffsets, UT);
   if (DD->getDwarfVersion() >= 5 && UT != dwarf::DW_UT_compile)
     Asm->emitInt64(getDWOId());
@@ -1783,7 +1787,8 @@ bool DwarfCompileUnit::isDwoUnit() const {
   return DD->useSplitDwarf() && Skeleton;
 }
 
-void DwarfCompileUnit::finishNonUnitTypeDIE(DIE& D, const DICompositeType *CTy) {
+void DwarfCompileUnit::finishNonUnitTypeDIE(DIE &D,
+                                            const DICompositeType *CTy) {
   constructTypeDIE(D, CTy);
 }
 
@@ -1817,11 +1822,12 @@ void DwarfCompileUnit::createBaseTypeDIEs() {
   // child list.
   for (auto &Btr : reverse(ExprRefedBaseTypes)) {
     DIE &Die = getUnitDie().addChildFront(
-      DIE::get(DIEValueAllocator, dwarf::DW_TAG_base_type));
+        DIE::get(DIEValueAllocator, dwarf::DW_TAG_base_type));
     SmallString<32> Str;
     addString(Die, dwarf::DW_AT_name,
-              Twine(dwarf::AttributeEncodingString(Btr.Encoding) +
-                    "_" + Twine(Btr.BitSize)).toStringRef(Str));
+              Twine(dwarf::AttributeEncodingString(Btr.Encoding) + "_" +
+                    Twine(Btr.BitSize))
+                  .toStringRef(Str));
     addUInt(Die, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, Btr.Encoding);
     // Round up to smallest number of bytes that contains this number of bits.
     // ExprRefedBaseTypes is populated with types referenced by
diff --git a/llvm/test/DebugInfo/X86/empty-struct-no-crash.ll b/llvm/test/DebugInfo/X86/empty-struct-no-crash.ll
new file mode 100644
index 0000000000000..5723cd7094a57
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/empty-struct-no-crash.ll
@@ -0,0 +1,28 @@
+; RUN: llc -mtriple=x86_64-apple-darwin -o /dev/null %s
+; Verify we don't crash on DISubprogram without a type in LineTablesOnly mode.
+
+target triple = "x86_64-apple-darwin"
+
+define void @test_empty_struct_debug() !dbg !4 {
+entry:
+  %tmp = alloca { { i1, {} }, ptr, { { {} }, { {} } }, i64 }, align 8
+    #dbg_value({ { {} }, { {} } } zeroinitializer, !5, !DIExpression(), !6)
+    #dbg_value(i64 2, !7, !DIExpression(), !6)
+  %0 = insertvalue { { i1, {} }, ptr, { { {} }, { {} } }, i64 } { { i1, {} } zeroinitializer, ptr null, { { {} }, { {} } } zeroinitializer, i64 2 }, ptr null, 1, !dbg !6
+  %1 = insertvalue { { i1, {} }, ptr, { { {} }, { {} } }, i64 } %0, { i1, {} } zeroinitializer, 0, !dbg !8
+  store { { i1, {} }, ptr, { { {} }, { {} } }, i64 } %1, ptr %tmp, align 8
+  ret void
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, isOptimized: false, runtimeVersion: 0, emissionKind: LineTablesOnly)
+!1 = !DIFile(filename: "test.cpp", directory: "/tmp")
+!2 = !{i32 2, !"Debug Info Version", i32 3}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = distinct !DISubprogram(name: "test_empty_struct_debug", scope: !1, file: !1, line: 1, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0)
+!5 = !DILocalVariable(name: "v1", scope: !4, file: !1, line: 2)
+!6 = !DILocation(line: 2, column: 1, scope: !4)
+!7 = !DILocalVariable(name: "v2", scope: !4, file: !1, line: 3)
+!8 = !DILocation(line: 3, column: 1, scope: !4)

``````````

</details>


https://github.com/llvm/llvm-project/pull/184299


More information about the llvm-commits mailing list