Skip to content

Commit 9f27948

Browse files
authored
Merge pull request #63011 from atrick/fix-sil-verify
Fix SILOwnershipVerifier exponential run time and out-of-memory.
2 parents f7a10cf + 7a0fd08 commit 9f27948

File tree

2 files changed

+128
-7
lines changed

2 files changed

+128
-7
lines changed

lib/SIL/Verifier/SILOwnershipVerifier.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -288,13 +288,22 @@ bool SILValueOwnershipChecker::gatherUsers(
288288
// Ok, we have some sort of borrow introducer. We need to recursively validate
289289
// that all of its uses (including sub-scopes) are before any end_borrows that
290290
// may end the lifetime of the borrow introducer. With that in mind, gather up
291-
// our initial list of users.
292-
SmallVector<Operand *, 8> users;
293-
llvm::copy(value->getUses(), std::back_inserter(users));
291+
// our initial list of uses.
292+
ValueSet visitedValues(value->getFunction());
293+
SmallVector<Operand *, 8> uses;
294+
auto pushUses = [&](SILValue val) {
295+
if (!visitedValues.insert(val))
296+
return;
297+
298+
for (Operand *use : val->getUses()) {
299+
uses.push_back(use);
300+
}
301+
};
302+
pushUses(value);
294303

295304
bool foundError = false;
296-
while (!users.empty()) {
297-
Operand *op = users.pop_back_val();
305+
while (!uses.empty()) {
306+
Operand *op = uses.pop_back_val();
298307
SILInstruction *user = op->getUser();
299308

300309
// If this op is a type dependent operand, skip it. It is not interesting
@@ -416,7 +425,7 @@ bool SILValueOwnershipChecker::gatherUsers(
416425
assert(result->getOwnershipKind() == OwnershipKind::Guaranteed &&
417426
"Our value is guaranteed and this is a forwarding instruction. "
418427
"Should have guaranteed ownership as well.");
419-
llvm::copy(result->getUses(), std::back_inserter(users));
428+
pushUses(result);
420429
}
421430
continue;
422431
}
@@ -452,7 +461,7 @@ bool SILValueOwnershipChecker::gatherUsers(
452461

453462
// Otherwise add all users of this BBArg to the worklist to visit
454463
// recursively.
455-
llvm::copy(succArg->getUses(), std::back_inserter(users));
464+
pushUses(succArg);
456465
}
457466
}
458467

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s
2+
3+
sil_stage canonical
4+
5+
import Builtin
6+
7+
class C {}
8+
9+
struct PairC {
10+
var first: C
11+
var second: C
12+
}
13+
14+
// Ensure that forwarding chains don't result in exponential run time.
15+
//
16+
sil [ossa] @testSSALongForwardingChain : $@convention(thin) (@guaranteed C) -> () {
17+
bb0(%0 : @guaranteed $C):
18+
test_specification "ssa-liveness @trace[0]"
19+
debug_value [trace] %0 : $C
20+
%s0 = struct $PairC(%0 : $C, %0 : $C)
21+
%s0a = struct_extract %s0 : $PairC, #PairC.first
22+
%s0b = struct_extract %s0 : $PairC, #PairC.second
23+
%s1 = struct $PairC(%s0a : $C, %s0b : $C)
24+
%s1a = struct_extract %s1 : $PairC, #PairC.first
25+
%s1b = struct_extract %s1 : $PairC, #PairC.second
26+
%s2 = struct $PairC(%s1a : $C, %s1b : $C)
27+
%s2a = struct_extract %s2 : $PairC, #PairC.first
28+
%s2b = struct_extract %s2 : $PairC, #PairC.second
29+
%s3 = struct $PairC(%s2a : $C, %s2b : $C)
30+
%s3a = struct_extract %s3 : $PairC, #PairC.first
31+
%s3b = struct_extract %s3 : $PairC, #PairC.second
32+
%s4 = struct $PairC(%s3a : $C, %s3b : $C)
33+
%s4a = struct_extract %s4 : $PairC, #PairC.first
34+
%s4b = struct_extract %s4 : $PairC, #PairC.second
35+
%s5 = struct $PairC(%s4a : $C, %s4b : $C)
36+
%s5a = struct_extract %s5 : $PairC, #PairC.first
37+
%s5b = struct_extract %s5 : $PairC, #PairC.second
38+
%s6 = struct $PairC(%s5a : $C, %s5b : $C)
39+
%s6a = struct_extract %s6 : $PairC, #PairC.first
40+
%s6b = struct_extract %s6 : $PairC, #PairC.second
41+
%s7 = struct $PairC(%s6a : $C, %s6b : $C)
42+
%s7a = struct_extract %s7 : $PairC, #PairC.first
43+
%s7b = struct_extract %s7 : $PairC, #PairC.second
44+
%s8 = struct $PairC(%s7a : $C, %s7b : $C)
45+
%s8a = struct_extract %s8 : $PairC, #PairC.first
46+
%s8b = struct_extract %s8 : $PairC, #PairC.second
47+
%s9 = struct $PairC(%s8a : $C, %s8b : $C)
48+
%s9a = struct_extract %s9 : $PairC, #PairC.first
49+
%s9b = struct_extract %s9 : $PairC, #PairC.second
50+
%s10 = struct $PairC(%s9a : $C, %s9b : $C)
51+
%s10a = struct_extract %s10 : $PairC, #PairC.first
52+
%s10b = struct_extract %s10 : $PairC, #PairC.second
53+
%s11 = struct $PairC(%s10a : $C, %s10b : $C)
54+
%s11a = struct_extract %s11 : $PairC, #PairC.first
55+
%s11b = struct_extract %s11 : $PairC, #PairC.second
56+
%s12 = struct $PairC(%s11a : $C, %s11b : $C)
57+
%s12a = struct_extract %s12 : $PairC, #PairC.first
58+
%s12b = struct_extract %s12 : $PairC, #PairC.second
59+
%s13 = struct $PairC(%s12a : $C, %s12b : $C)
60+
%s13a = struct_extract %s13 : $PairC, #PairC.first
61+
%s13b = struct_extract %s13 : $PairC, #PairC.second
62+
%s14 = struct $PairC(%s13a : $C, %s13b : $C)
63+
%s14a = struct_extract %s14 : $PairC, #PairC.first
64+
%s14b = struct_extract %s14 : $PairC, #PairC.second
65+
%s15 = struct $PairC(%s14a : $C, %s14b : $C)
66+
%s15a = struct_extract %s15 : $PairC, #PairC.first
67+
%s15b = struct_extract %s15 : $PairC, #PairC.second
68+
%s16 = struct $PairC(%s15a : $C, %s15b : $C)
69+
%s16a = struct_extract %s16 : $PairC, #PairC.first
70+
%s16b = struct_extract %s16 : $PairC, #PairC.second
71+
%s17 = struct $PairC(%s16a : $C, %s16b : $C)
72+
%s17a = struct_extract %s17 : $PairC, #PairC.first
73+
%s17b = struct_extract %s17 : $PairC, #PairC.second
74+
%s18 = struct $PairC(%s17a : $C, %s17b : $C)
75+
%s18a = struct_extract %s18 : $PairC, #PairC.first
76+
%s18b = struct_extract %s18 : $PairC, #PairC.second
77+
%s19 = struct $PairC(%s18a : $C, %s18b : $C)
78+
%s19a = struct_extract %s19 : $PairC, #PairC.first
79+
%s19b = struct_extract %s19 : $PairC, #PairC.second
80+
%s20 = struct $PairC(%s19a : $C, %s19b : $C)
81+
%s20a = struct_extract %s20 : $PairC, #PairC.first
82+
%s20b = struct_extract %s20 : $PairC, #PairC.second
83+
%s21 = struct $PairC(%s20a : $C, %s20b : $C)
84+
%s21a = struct_extract %s21 : $PairC, #PairC.first
85+
%s21b = struct_extract %s21 : $PairC, #PairC.second
86+
%s22 = struct $PairC(%s21a : $C, %s21b : $C)
87+
%s22a = struct_extract %s22 : $PairC, #PairC.first
88+
%s22b = struct_extract %s22 : $PairC, #PairC.second
89+
%s23 = struct $PairC(%s22a : $C, %s22b : $C)
90+
%s23a = struct_extract %s23 : $PairC, #PairC.first
91+
%s23b = struct_extract %s23 : $PairC, #PairC.second
92+
%s24 = struct $PairC(%s23a : $C, %s23b : $C)
93+
%s24a = struct_extract %s24 : $PairC, #PairC.first
94+
%s24b = struct_extract %s24 : $PairC, #PairC.second
95+
%s25 = struct $PairC(%s24a : $C, %s24b : $C)
96+
%s25a = struct_extract %s25 : $PairC, #PairC.first
97+
%s25b = struct_extract %s25 : $PairC, #PairC.second
98+
%s26 = struct $PairC(%s25a : $C, %s25b : $C)
99+
%s26a = struct_extract %s26 : $PairC, #PairC.first
100+
%s26b = struct_extract %s26 : $PairC, #PairC.second
101+
%s27 = struct $PairC(%s26a : $C, %s26b : $C)
102+
%s27a = struct_extract %s27 : $PairC, #PairC.first
103+
%s27b = struct_extract %s27 : $PairC, #PairC.second
104+
%s28 = struct $PairC(%s27a : $C, %s27b : $C)
105+
%s28a = struct_extract %s28 : $PairC, #PairC.first
106+
%s28b = struct_extract %s28 : $PairC, #PairC.second
107+
%s29 = struct $PairC(%s28a : $C, %s28b : $C)
108+
%s29a = struct_extract %s29 : $PairC, #PairC.first
109+
%s29b = struct_extract %s29 : $PairC, #PairC.second
110+
%99 = tuple()
111+
return %99 : $()
112+
}

0 commit comments

Comments
 (0)