Skip to content

Commit a8dfac4

Browse files
committed
[ownership] Use the new LinearLifetimeError to propagate back to callers why the checker failed.
1 parent 86de35b commit a8dfac4

File tree

2 files changed

+42
-21
lines changed

2 files changed

+42
-21
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,26 @@ struct ErrorBehaviorKind {
6969

7070
class LinearLifetimeError {
7171
ownership::ErrorBehaviorKind errorBehavior;
72-
bool foundError = false;
72+
bool foundUseAfterFree = false;
73+
bool foundLeak = false;
74+
bool foundOverConsume = false;
7375

7476
public:
7577
LinearLifetimeError(ownership::ErrorBehaviorKind errorBehavior)
7678
: errorBehavior(errorBehavior) {}
7779

78-
bool getFoundError() const { return foundError; }
80+
bool getFoundError() const {
81+
return foundUseAfterFree || foundLeak || foundOverConsume;
82+
}
83+
84+
bool getFoundLeak() const { return foundLeak; }
85+
86+
bool getFoundUseAfterFree() const { return foundUseAfterFree; }
7987

80-
void handleLeakError(llvm::function_ref<void()> &&messagePrinterFunc) {
81-
foundError = true;
88+
bool getFoundOverConsume() const { return foundOverConsume; }
89+
90+
void handleLeak(llvm::function_ref<void()> &&messagePrinterFunc) {
91+
foundLeak = true;
8292

8393
if (errorBehavior.shouldPrintMessage())
8494
messagePrinterFunc();
@@ -90,9 +100,18 @@ class LinearLifetimeError {
90100
handleError([]() {});
91101
}
92102

93-
void handleError(llvm::function_ref<void()> &&messagePrinterFunc) {
94-
foundError = true;
103+
void handleOverConsume(llvm::function_ref<void()> &&messagePrinterFunc) {
104+
foundOverConsume = true;
105+
handleError(std::move(messagePrinterFunc));
106+
}
107+
108+
void handleUseAfterFree(llvm::function_ref<void()> &&messagePrinterFunc) {
109+
foundUseAfterFree = true;
110+
handleError(std::move(messagePrinterFunc));
111+
}
95112

113+
private:
114+
void handleError(llvm::function_ref<void()> &&messagePrinterFunc) {
96115
if (errorBehavior.shouldPrintMessage())
97116
messagePrinterFunc();
98117

lib/SIL/LinearLifetimeChecker.cpp

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,6 @@ struct State {
111111
/// for validity. If this is a linear typed value, return true. Return false
112112
/// otherwise.
113113
bool checkDataflowEndState(DeadEndBlocks &deBlocks);
114-
115-
/// Depending on our initialization, either return false or call Func and
116-
/// throw an error.
117-
bool handleError(llvm::function_ref<void()> &&messagePrinterFunc) {
118-
error.handleError(std::move(messagePrinterFunc));
119-
return false;
120-
}
121114
};
122115

123116
} // end anonymous namespace
@@ -210,7 +203,7 @@ void State::initializeConsumingUse(BranchPropagatedUser consumingUser,
210203
if (blocksWithConsumingUses.insert(userBlock).second)
211204
return;
212205

213-
handleError([&] {
206+
error.handleOverConsume([&] {
214207
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
215208
<< "Found over consume?!\n"
216209
<< "Value: " << *value << "User: " << *consumingUser
@@ -235,7 +228,7 @@ void State::checkForSameBlockUseAfterFree(BranchPropagatedUser consumingUser,
235228
// always consider the non-consuming use to be a use after free since
236229
// the cond branch user is in a previous block. So just bail early.
237230
if (consumingUser.isCondBranchUser()) {
238-
handleError([&]() {
231+
error.handleUseAfterFree([&]() {
239232
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
240233
<< "Found use after free?!\n"
241234
<< "Value: " << *value
@@ -262,7 +255,7 @@ void State::checkForSameBlockUseAfterFree(BranchPropagatedUser consumingUser,
262255
[&nonConsumingUser](const SILInstruction &i) -> bool {
263256
return nonConsumingUser == &i;
264257
}) != userBlock->end()) {
265-
handleError([&] {
258+
error.handleUseAfterFree([&] {
266259
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
267260
<< "Found use after free?!\n"
268261
<< "Value: " << *value
@@ -283,24 +276,29 @@ bool State::checkPredsForDoubleConsume(BranchPropagatedUser consumingUser,
283276
if (!blocksWithConsumingUses.count(userBlock))
284277
return false;
285278

286-
return !handleError([&] {
279+
error.handleOverConsume([&] {
287280
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
288281
<< "Found over consume?!\n"
289282
<< "Value: " << *value << "User: " << *consumingUser
290283
<< "Block: bb" << userBlock->getDebugID() << "\n\n";
291284
});
285+
286+
// If we reached this point, then we did not assert, but we did flag an
287+
// error. Return true so we continue the walk.
288+
return true;
292289
}
293290

294291
bool State::checkPredsForDoubleConsume(SILBasicBlock *userBlock) {
295292
if (!blocksWithConsumingUses.count(userBlock))
296293
return false;
297294

298-
return !handleError([&] {
295+
error.handleOverConsume([&] {
299296
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
300297
<< "Found over consume?!\n"
301298
<< "Value: " << *value << "Block: bb"
302299
<< userBlock->getDebugID() << "\n\n";
303300
});
301+
return true;
304302
}
305303

306304
//===----------------------------------------------------------------------===//
@@ -367,8 +365,11 @@ bool State::performDataflow(DeadEndBlocks &deBlocks) {
367365
//
368366
// 2. We add the predecessor to the worklist if we have not visited it yet.
369367
for (auto *predBlock : block->getPredecessorBlocks()) {
368+
// Check if we have an over consume.
370369
if (checkPredsForDoubleConsume(predBlock)) {
371-
return handleError([] {});
370+
// If we were to assert, it is handled inside check preds for double
371+
// consume. So just return false so that we bail.
372+
return false;
372373
}
373374

374375
if (visitedBlocks.count(predBlock)) {
@@ -397,7 +398,7 @@ bool State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
397398
}
398399

399400
// If we are supposed to error on leaks, do so now.
400-
error.handleLeakError([&] {
401+
error.handleLeak([&] {
401402
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
402403
<< "Error! Found a leak due to a consuming post-dominance "
403404
"failure!\n"
@@ -427,7 +428,7 @@ bool State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
427428
continue;
428429
}
429430

430-
return handleError([&] {
431+
error.handleUseAfterFree([&] {
431432
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
432433
<< "Found use after free due to unvisited non lifetime "
433434
"ending uses?!\n"
@@ -438,6 +439,7 @@ bool State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
438439
}
439440
llvm::errs() << "\n";
440441
});
442+
return false;
441443
}
442444

443445
// If all of our remaining blocks were dead uses, then return true. We are

0 commit comments

Comments
 (0)