Skip to content

Commit e2a2c03

Browse files
authored
[DebugInfo] Add Verifier check for incorrectly-scoped retainedNodes (#166855)
These checks ensure that retained nodes of a DISubprogram belong to the subprogram. Tests with incorrect IR are fixed. We should not have variables of one subprogram present in retained nodes of other subprograms. 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)) ... ```
1 parent bfd4155 commit e2a2c03

24 files changed

+129
-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: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2554,6 +2554,39 @@ 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+
if (const auto *L = dyn_cast<DILabel>(N))
2567+
return FuncLabel(L);
2568+
if (const auto *IE = dyn_cast<DIImportedEntity>(N))
2569+
return FuncIE(IE);
2570+
return FuncUnknown(N);
2571+
}
2572+
2573+
/// Returns the scope of subprogram's retainedNodes.
2574+
static const DILocalScope *getRetainedNodeScope(const MDNode *N);
2575+
// For use in Verifier.
2576+
static const DIScope *getRawRetainedNodeScope(const MDNode *N);
2577+
2578+
/// For each retained node, applies one of the given functions depending
2579+
/// on the type of a node.
2580+
template <typename FuncLVT, typename FuncLabelT, typename FuncImportedEntityT>
2581+
void forEachRetainedNode(FuncLVT &&FuncLV, FuncLabelT &&FuncLabel,
2582+
FuncImportedEntityT &&FuncIE) const {
2583+
for (MDNode *N : getRetainedNodes())
2584+
visitRetainedNode<void>(N, FuncLV, FuncLabel, FuncIE,
2585+
[](const Metadata *N) {
2586+
llvm_unreachable("Unexpected retained node!");
2587+
});
2588+
}
2589+
25572590
/// Check if this subprogram describes the given function.
25582591
///
25592592
/// 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)