diff options
author | Aaron Puchert <aaronpuchert@alice-dsl.net> | 2018-10-06 01:09:28 +0000 |
---|---|---|
committer | Aaron Puchert <aaronpuchert@alice-dsl.net> | 2018-10-06 01:09:28 +0000 |
commit | b0a2a0cf7dddcb79074767f59401859c6ff30fab (patch) | |
tree | 7b3f5eda870185c7a4b9756c8d11440926a8033b /clang | |
parent | 34c0e470ae30d7205ad257a56db7e8c588edd3d5 (diff) | |
download | bcm5719-llvm-b0a2a0cf7dddcb79074767f59401859c6ff30fab.tar.gz bcm5719-llvm-b0a2a0cf7dddcb79074767f59401859c6ff30fab.zip |
Thread safety analysis: Handle conditional expression in getTrylockCallExpr
Summary:
We unwrap conditional expressions containing try-lock functions.
Additionally we don't acquire on conditional expression branches, since
that is usually not helpful. When joining the branches we would almost
certainly get a warning then.
Hopefully fixes an issue that was raised in D52398.
Reviewers: aaron.ballman, delesley, hokein
Reviewed By: aaron.ballman
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D52888
llvm-svn: 343902
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/Analysis/ThreadSafety.cpp | 14 | ||||
-rw-r--r-- | clang/test/SemaCXX/warn-thread-safety-analysis.cpp | 17 |
2 files changed, 30 insertions, 1 deletions
diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp index 846dc80a4d0..dad2417d8e6 100644 --- a/clang/lib/Analysis/ThreadSafety.cpp +++ b/clang/lib/Analysis/ThreadSafety.cpp @@ -1435,6 +1435,17 @@ const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(const Stmt *Cond, if (BOP->getOpcode() == BO_LOr) return getTrylockCallExpr(BOP->getRHS(), C, Negate); return nullptr; + } else if (const auto *COP = dyn_cast<ConditionalOperator>(Cond)) { + bool TCond, FCond; + if (getStaticBooleanValue(COP->getTrueExpr(), TCond) && + getStaticBooleanValue(COP->getFalseExpr(), FCond)) { + if (TCond && !FCond) + return getTrylockCallExpr(COP->getCond(), C, Negate); + if (!TCond && FCond) { + Negate = !Negate; + return getTrylockCallExpr(COP->getCond(), C, Negate); + } + } } return nullptr; } @@ -1449,7 +1460,8 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result, Result = ExitSet; const Stmt *Cond = PredBlock->getTerminatorCondition(); - if (!Cond) + // We don't acquire try-locks on ?: branches, only when its result is used. + if (!Cond || isa<ConditionalOperator>(PredBlock->getTerminator())) return; bool Negate = false; diff --git a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp index 9df0e2a3b4d..54e3369f4d3 100644 --- a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp +++ b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp @@ -1873,6 +1873,23 @@ struct TestTryLock { int i = a; mu.Unlock(); } + + // Test with conditional operator + void foo13() { + if (mu.TryLock() ? 1 : 0) + mu.Unlock(); + } + + void foo14() { + if (mu.TryLock() ? 0 : 1) + return; + mu.Unlock(); + } + + void foo15() { + if (mu.TryLock() ? 0 : 1) // expected-note{{mutex acquired here}} + mu.Unlock(); // expected-warning{{releasing mutex 'mu' that was not held}} + } // expected-warning{{mutex 'mu' is not held on every path through here}} }; // end TestTrylock } // end namespace TrylockTest |