Skip to content

Commit 42ce245

Browse files
committed
[DebugInfo] Add Verifier check for incorrectly-scoped retainedNodes
These checks ensure that retained nodes of a DISubprogram belong to the subprogram. This was helpful to find issues with https://reviews.llvm.org/D144004, llvm#75385, llvm#165032. Also, interface for accessing DISubprogram's retained nodes is slightly refactored. `DISubprogram::visitRetainedNodes` and `DISubprogram::forEachRetainedNode` are added to avoid repeating checks like ``` if (const auto *LV = dyn_cast<DILocalVariable>(N)) ... else if (const auto *L = dyn_cast<DILabel>(N)) ... else if (const auto *IE = dyn_cast<DIImportedEntity>(N)) ... ``` Tests with wrongly scoped retained nodes are fixed.
1 parent bb6d2be commit 42ce245

24 files changed

+130
-69
lines changed

llvm/include/llvm/IR/DebugInfo.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class DebugInfoFinder {
108108
LLVM_ABI void processInstruction(const Module &M, const Instruction &I);
109109

110110
/// Process a DILocalVariable.
111-
LLVM_ABI void processVariable(DILocalVariable *DVI);
111+
LLVM_ABI void processVariable(const DILocalVariable *DVI);
112112
/// Process debug info location.
113113
LLVM_ABI void processLocation(const Module &M, const DILocation *Loc);
114114
/// Process a DbgRecord.
@@ -124,7 +124,7 @@ class DebugInfoFinder {
124124
void processCompileUnit(DICompileUnit *CU);
125125
void processScope(DIScope *Scope);
126126
void processType(DIType *DT);
127-
void processImportedEntity(DIImportedEntity *Import);
127+
void processImportedEntity(const DIImportedEntity *Import);
128128
bool addCompileUnit(DICompileUnit *CU);
129129
bool addGlobalVariable(DIGlobalVariableExpression *DIG);
130130
bool addScope(DIScope *Scope);

llvm/include/llvm/IR/DebugInfoMetadata.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2554,6 +2554,40 @@ class DISubprogram : public DILocalScope {
25542554
replaceOperandWith(7, N.get());
25552555
}
25562556

2557+
/// For the given retained node of DISubprogram, applies one of the
2558+
/// given functions depending on the type of the node.
2559+
template <typename T, typename FuncLVT, typename FuncLabelT,
2560+
typename FuncImportedEntityT, typename FuncUnknownT>
2561+
static T
2562+
visitRetainedNode(const Metadata *N, FuncLVT &&FuncLV, FuncLabelT &&FuncLabel,
2563+
FuncImportedEntityT &&FuncIE, FuncUnknownT &&FuncUnknown) {
2564+
if (const auto *LV = dyn_cast<DILocalVariable>(N))
2565+
return FuncLV(LV);
2566+
else if (const auto *L = dyn_cast<DILabel>(N))
2567+
return FuncLabel(L);
2568+
else if (const auto *IE = dyn_cast<DIImportedEntity>(N))
2569+
return FuncIE(IE);
2570+
else
2571+
return FuncUnknown(N);
2572+
}
2573+
2574+
/// Returns the scope of subprogram's retainedNodes.
2575+
static const DILocalScope *getRetainedNodeScope(const MDNode *N);
2576+
// For use in Verifier.
2577+
static const DIScope *getRawRetainedNodeScope(const MDNode *N);
2578+
2579+
/// For each retained node, applies one of the given functions depending
2580+
/// on the type of a node.
2581+
template <typename FuncLVT, typename FuncLabelT, typename FuncImportedEntityT>
2582+
void forEachRetainedNode(FuncLVT &&FuncLV, FuncLabelT &&FuncLabel,
2583+
FuncImportedEntityT &&FuncIE) const {
2584+
for (MDNode *N : getRetainedNodes())
2585+
visitRetainedNode<void>(N, FuncLV, FuncLabel, FuncIE,
2586+
[](const Metadata *N) {
2587+
llvm_unreachable("Unexpected retained node!");
2588+
});
2589+
}
2590+
25572591
/// Check if this subprogram describes the given function.
25582592
///
25592593
/// FIXME: Should this be looking through bitcasts?

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,18 +1544,8 @@ void DwarfDebug::ensureAbstractEntityIsCreatedIfScoped(DwarfCompileUnit &CU,
15441544
}
15451545

15461546
static const DILocalScope *getRetainedNodeScope(const MDNode *N) {
1547-
const DIScope *S;
1548-
if (const auto *LV = dyn_cast<DILocalVariable>(N))
1549-
S = LV->getScope();
1550-
else if (const auto *L = dyn_cast<DILabel>(N))
1551-
S = L->getScope();
1552-
else if (const auto *IE = dyn_cast<DIImportedEntity>(N))
1553-
S = IE->getScope();
1554-
else
1555-
llvm_unreachable("Unexpected retained node!");
1556-
15571547
// Ensure the scope is not a DILexicalBlockFile.
1558-
return cast<DILocalScope>(S)->getNonLexicalBlockFileScope();
1548+
return DISubprogram::getRetainedNodeScope(N)->getNonLexicalBlockFileScope();
15591549
}
15601550

15611551
// Collect variable information from side table maintained by MF.

llvm/lib/IR/DebugInfo.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ void DebugInfoFinder::processType(DIType *DT) {
247247
}
248248
}
249249

250-
void DebugInfoFinder::processImportedEntity(DIImportedEntity *Import) {
250+
void DebugInfoFinder::processImportedEntity(const DIImportedEntity *Import) {
251251
auto *Entity = Import->getEntity();
252252
if (auto *T = dyn_cast<DIType>(Entity))
253253
processType(T);
@@ -307,15 +307,13 @@ void DebugInfoFinder::processSubprogram(DISubprogram *SP) {
307307
}
308308
}
309309

310-
for (auto *N : SP->getRetainedNodes()) {
311-
if (auto *Var = dyn_cast_or_null<DILocalVariable>(N))
312-
processVariable(Var);
313-
else if (auto *Import = dyn_cast_or_null<DIImportedEntity>(N))
314-
processImportedEntity(Import);
315-
}
310+
SP->forEachRetainedNode(
311+
[this](const DILocalVariable *LV) { processVariable(LV); },
312+
[](const DILabel *L) {},
313+
[this](const DIImportedEntity *IE) { processImportedEntity(IE); });
316314
}
317315

318-
void DebugInfoFinder::processVariable(DILocalVariable *DV) {
316+
void DebugInfoFinder::processVariable(const DILocalVariable *DV) {
319317
if (!NodesSeen.insert(DV).second)
320318
return;
321319
processScope(DV->getScope());

llvm/lib/IR/DebugInfoMetadata.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,6 +1441,19 @@ bool DISubprogram::describes(const Function *F) const {
14411441
assert(F && "Invalid function");
14421442
return F->getSubprogram() == this;
14431443
}
1444+
1445+
const DIScope *DISubprogram::getRawRetainedNodeScope(const MDNode *N) {
1446+
return visitRetainedNode<DIScope *>(
1447+
N, [](const DILocalVariable *LV) { return LV->getScope(); },
1448+
[](const DILabel *L) { return L->getScope(); },
1449+
[](const DIImportedEntity *IE) { return IE->getScope(); },
1450+
[](const Metadata *N) { return nullptr; });
1451+
}
1452+
1453+
const DILocalScope *DISubprogram::getRetainedNodeScope(const MDNode *N) {
1454+
return cast<DILocalScope>(getRawRetainedNodeScope(N));
1455+
}
1456+
14441457
DILexicalBlockBase::DILexicalBlockBase(LLVMContext &C, unsigned ID,
14451458
StorageType Storage,
14461459
ArrayRef<Metadata *> Ops)

llvm/lib/IR/Verifier.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,11 +1559,27 @@ void Verifier::visitDISubprogram(const DISubprogram &N) {
15591559
auto *Node = dyn_cast<MDTuple>(RawNode);
15601560
CheckDI(Node, "invalid retained nodes list", &N, RawNode);
15611561
for (Metadata *Op : Node->operands()) {
1562-
CheckDI(Op && (isa<DILocalVariable>(Op) || isa<DILabel>(Op) ||
1563-
isa<DIImportedEntity>(Op)),
1562+
CheckDI(Op, "nullptr in retained nodes", &N, Node);
1563+
1564+
auto True = [](const Metadata *) { return true; };
1565+
auto False = [](const Metadata *) { return false; };
1566+
bool IsTypeCorrect =
1567+
DISubprogram::visitRetainedNode<bool>(Op, True, True, True, False);
1568+
CheckDI(IsTypeCorrect,
15641569
"invalid retained nodes, expected DILocalVariable, DILabel or "
15651570
"DIImportedEntity",
15661571
&N, Node, Op);
1572+
1573+
auto *RetainedNode = cast<DINode>(Op);
1574+
auto *RetainedNodeScope = dyn_cast_or_null<DILocalScope>(
1575+
DISubprogram::getRawRetainedNodeScope(RetainedNode));
1576+
CheckDI(RetainedNodeScope,
1577+
"invalid retained nodes, retained node is not local", &N, Node,
1578+
RetainedNode);
1579+
CheckDI(
1580+
RetainedNodeScope->getSubprogram() == &N,
1581+
"invalid retained nodes, retained node does not belong to subprogram",
1582+
&N, Node, RetainedNode, RetainedNodeScope);
15671583
}
15681584
}
15691585
CheckDI(!hasConflictingReferenceFlags(N.getFlags()),

llvm/test/CodeGen/X86/StackColoring-dbg-invariance.mir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
!9 = !DILocalVariable(name: "4", scope: !5, file: !1, line: 4, type: !10)
5656
!10 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_unsigned)
5757
!11 = !DILocation(line: 4, column: 1, scope: !5)
58-
!12 = distinct !DISubprogram(name: "test_2", linkageName: "test_2", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
58+
!12 = distinct !DISubprogram(name: "test_2", linkageName: "test_2", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !7)
5959

6060
...
6161
---

llvm/test/DebugInfo/MIR/X86/clobbered-fragments.mir

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,11 @@
8585
!15 = !DISubrange(count: 3)
8686
!16 = !DILocation(line: 8, scope: !8)
8787
!17 = !DILocation(line: 9, scope: !8)
88-
!18 = distinct !DISubprogram(name: "test2", scope: !2, file: !2, line: 7, type: !9, scopeLine: 7, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !1, retainedNodes: !11)
88+
!18 = distinct !DISubprogram(name: "test2", scope: !2, file: !2, line: 7, type: !9, scopeLine: 7, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !1, retainedNodes: !22)
8989
!19 = !DILocalVariable(name: "local", scope: !18, file: !2, line: 8, type: !13)
9090
!20 = !DILocation(line: 15, scope: !18)
9191
!21 = !DILocation(line: 16, scope: !18)
92+
!22 = !{!19}
9293

9394
...
9495
---

llvm/test/DebugInfo/MIR/X86/machine-cse.mir

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,14 @@
7373
!0 = !{i32 2, !"Debug Info Version", i32 3}
7474
!1 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !2, producer: "beards", isOptimized: true, runtimeVersion: 4, emissionKind: FullDebug)
7575
!2 = !DIFile(filename: "bees.cpp", directory: "")
76-
!3 = distinct !DISubprogram(name: "nope", scope: !1, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !8)
77-
!33 = distinct !DISubprogram(name: "alsonope", scope: !1, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !8)
76+
!3 = distinct !DISubprogram(name: "nope", scope: !1, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !9)
77+
!33 = distinct !DISubprogram(name: "alsonope", scope: !1, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !9)
7878
!4 = !DILocalVariable(name: "bees", scope: !3, type: !5)
7979
!5 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64)
8080
!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
8181
!7 = !DILocation(line: 0, scope: !3)
8282
!8 = !{!4}
83+
!9 = !{}
8384

8485

8586
; CHECK: ![[METAVAR:[0-9]+]] = !DILocalVariable(name: "bees",

llvm/test/DebugInfo/MIR/X86/remove-redundant-dbg-vals.mir

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,15 @@
139139
!23 = !DISubprogram(name: "bar", scope: !1, file: !1, line: 1, type: !24, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
140140
!24 = !DISubroutineType(types: !25)
141141
!25 = !{null, !11}
142-
!26 = distinct !DISubprogram(name: "foo2", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
142+
!26 = distinct !DISubprogram(name: "foo2", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
143143
!27 = !DILocation(line: 0, scope: !26)
144-
!28 = distinct !DISubprogram(name: "foo3", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
144+
!28 = distinct !DISubprogram(name: "foo3", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
145145
!29 = !DILocation(line: 0, scope: !28)
146-
!30 = distinct !DISubprogram(name: "foo4", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
146+
!30 = distinct !DISubprogram(name: "foo4", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
147147
!31 = !DILocation(line: 0, scope: !30)
148-
!32 = distinct !DISubprogram(name: "foo5", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
148+
!32 = distinct !DISubprogram(name: "foo5", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
149149
!33 = !DILocation(line: 0, scope: !32)
150-
!34 = distinct !DISubprogram(name: "foo6", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
150+
!34 = distinct !DISubprogram(name: "foo6", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
151151
!35 = !DILocation(line: 0, scope: !34)
152152

153153
...

0 commit comments

Comments
 (0)