Skip to content

Commit b629d4b

Browse files
[Attributor] Prevent infinite loop in AAGlobalValueInfoFloating (#94941)
Global variables that reference themselves alongside a function that is called indirectly can cause an infinite loop in `AAGlobalValueInfoFloating`. The recursive reference is continually pushed back into the workload, causing the attributor to hang indefinitely.
1 parent 8520061 commit b629d4b

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

llvm/lib/Transforms/IPO/Attributor.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1749,6 +1749,10 @@ bool Attributor::checkForAllCallees(
17491749
return Pred(Callees.getArrayRef());
17501750
}
17511751

1752+
bool canMarkAsVisited(const User *Usr) {
1753+
return isa<PHINode>(Usr) || !isa<Instruction>(Usr);
1754+
}
1755+
17521756
bool Attributor::checkForAllUses(
17531757
function_ref<bool(const Use &, bool &)> Pred,
17541758
const AbstractAttribute &QueryingAA, const Value &V,
@@ -1796,7 +1800,7 @@ bool Attributor::checkForAllUses(
17961800

17971801
while (!Worklist.empty()) {
17981802
const Use *U = Worklist.pop_back_val();
1799-
if (isa<PHINode>(U->getUser()) && !Visited.insert(U).second)
1803+
if (canMarkAsVisited(U->getUser()) && !Visited.insert(U).second)
18001804
continue;
18011805
DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, {
18021806
if (auto *Fn = dyn_cast<Function>(U->getUser()))
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -passes=attributor -S < %s | FileCheck %s
3+
4+
; Global variables that reference themselves alongside a function that is called indirectly
5+
; used to cause an infinite loop in the attributor. The recursive reference was continually
6+
; pushed back into the workload, causing the attributor to hang indefinitely.
7+
8+
@glob1 = global { ptr, ptr } { ptr @glob1, ptr @fnc1 }
9+
@glob2 = global { ptr, ptr } { ptr @glob3, ptr @fnc2 }
10+
@glob3 = global { ptr, ptr } { ptr @glob2, ptr @fnc2 }
11+
12+
define internal void @fnc1() {
13+
; CHECK-LABEL: define internal void @fnc1(
14+
; CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
15+
; CHECK-NEXT: ret void
16+
;
17+
ret void
18+
}
19+
20+
define internal void @fnc2() {
21+
; CHECK-LABEL: define internal void @fnc2(
22+
; CHECK-SAME: ) #[[ATTR0]] {
23+
; CHECK-NEXT: ret void
24+
;
25+
ret void
26+
}
27+
28+
define dso_local void @indr_caller(ptr %0) {
29+
; CHECK-LABEL: define dso_local void @indr_caller(
30+
; CHECK-SAME: ptr nocapture nofree noundef nonnull [[TMP0:%.*]]) {
31+
; CHECK-NEXT: call void [[TMP0]]()
32+
; CHECK-NEXT: ret void
33+
;
34+
call void %0()
35+
ret void
36+
}
37+
38+
define void @main() {
39+
; CHECK-LABEL: define void @main() {
40+
; CHECK-NEXT: call void @indr_caller(ptr nocapture nofree noundef nonnull @fnc1)
41+
; CHECK-NEXT: call void @indr_caller(ptr nocapture nofree noundef nonnull @fnc2)
42+
; CHECK-NEXT: ret void
43+
;
44+
call void @indr_caller(ptr @fnc1)
45+
call void @indr_caller(ptr @fnc2)
46+
ret void
47+
}

0 commit comments

Comments
 (0)