summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
diff options
context:
space:
mode:
authorGabor Horvath <xazax.hun@gmail.com>2017-03-10 14:50:12 +0000
committerGabor Horvath <xazax.hun@gmail.com>2017-03-10 14:50:12 +0000
commit829c6bc04a6fd39845ada8498b149fdcc99139db (patch)
tree786313727479f5d0758ceaf7166a78fe470fa993 /clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
parente9313ba2defed881f8bc19922f9e6830afed8a19 (diff)
downloadbcm5719-llvm-829c6bc04a6fd39845ada8498b149fdcc99139db.tar.gz
bcm5719-llvm-829c6bc04a6fd39845ada8498b149fdcc99139db.zip
[analyzer] Extend block in critical section check with C11 and Pthread APIs.
Patch by Zoltan Daniel Torok! Differential Revision: https://reviews.llvm.org/D29567 llvm-svn: 297461
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp70
1 files changed, 57 insertions, 13 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
index 082a4873217..d19630eeef7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
@@ -29,7 +29,9 @@ namespace {
class BlockInCriticalSectionChecker : public Checker<check::PostCall,
check::PreCall> {
- CallDescription LockFn, UnlockFn, SleepFn, GetcFn, FgetsFn, ReadFn, RecvFn;
+ CallDescription LockFn, UnlockFn, SleepFn, GetcFn, FgetsFn, ReadFn, RecvFn,
+ PthreadLockFn, PthreadTryLockFn, PthreadUnlockFn,
+ MtxLock, MtxTimedLock, MtxTryLock, MtxUnlock;
std::unique_ptr<BugType> BlockInCritSectionBugType;
@@ -40,6 +42,10 @@ class BlockInCriticalSectionChecker : public Checker<check::PostCall,
public:
BlockInCriticalSectionChecker();
+ bool isBlockingFunction(const CallEvent &Call) const;
+ bool isLockFunction(const CallEvent &Call) const;
+ bool isUnlockFunction(const CallEvent &Call) const;
+
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
/// Process unlock.
@@ -55,34 +61,69 @@ REGISTER_TRAIT_WITH_PROGRAMSTATE(MutexCounter, unsigned)
BlockInCriticalSectionChecker::BlockInCriticalSectionChecker()
: LockFn("lock"), UnlockFn("unlock"), SleepFn("sleep"), GetcFn("getc"),
- FgetsFn("fgets"), ReadFn("read"), RecvFn("recv") {
+ FgetsFn("fgets"), ReadFn("read"), RecvFn("recv"),
+ PthreadLockFn("pthread_mutex_lock"),
+ PthreadTryLockFn("pthread_mutex_trylock"),
+ PthreadUnlockFn("pthread_mutex_unlock"),
+ MtxLock("mtx_lock"),
+ MtxTimedLock("mtx_timedlock"),
+ MtxTryLock("mtx_trylock"),
+ MtxUnlock("mtx_unlock") {
// Initialize the bug type.
BlockInCritSectionBugType.reset(
new BugType(this, "Call to blocking function in critical section",
"Blocking Error"));
}
+bool BlockInCriticalSectionChecker::isBlockingFunction(const CallEvent &Call) const {
+ if (Call.isCalled(SleepFn)
+ || Call.isCalled(GetcFn)
+ || Call.isCalled(FgetsFn)
+ || Call.isCalled(ReadFn)
+ || Call.isCalled(RecvFn)) {
+ return true;
+ }
+ return false;
+}
+
+bool BlockInCriticalSectionChecker::isLockFunction(const CallEvent &Call) const {
+ if (Call.isCalled(LockFn)
+ || Call.isCalled(PthreadLockFn)
+ || Call.isCalled(PthreadTryLockFn)
+ || Call.isCalled(MtxLock)
+ || Call.isCalled(MtxTimedLock)
+ || Call.isCalled(MtxTryLock)) {
+ return true;
+ }
+ return false;
+}
+
+bool BlockInCriticalSectionChecker::isUnlockFunction(const CallEvent &Call) const {
+ if (Call.isCalled(UnlockFn)
+ || Call.isCalled(PthreadUnlockFn)
+ || Call.isCalled(MtxUnlock)) {
+ return true;
+ }
+ return false;
+}
+
void BlockInCriticalSectionChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
}
void BlockInCriticalSectionChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
- if (!Call.isCalled(LockFn)
- && !Call.isCalled(SleepFn)
- && !Call.isCalled(GetcFn)
- && !Call.isCalled(FgetsFn)
- && !Call.isCalled(ReadFn)
- && !Call.isCalled(RecvFn)
- && !Call.isCalled(UnlockFn))
+ if (!isBlockingFunction(Call)
+ && !isLockFunction(Call)
+ && !isUnlockFunction(Call))
return;
ProgramStateRef State = C.getState();
unsigned mutexCount = State->get<MutexCounter>();
- if (Call.isCalled(UnlockFn) && mutexCount > 0) {
+ if (isUnlockFunction(Call) && mutexCount > 0) {
State = State->set<MutexCounter>(--mutexCount);
C.addTransition(State);
- } else if (Call.isCalled(LockFn)) {
+ } else if (isLockFunction(Call)) {
State = State->set<MutexCounter>(++mutexCount);
C.addTransition(State);
} else if (mutexCount > 0) {
@@ -97,8 +138,11 @@ void BlockInCriticalSectionChecker::reportBlockInCritSection(
if (!ErrNode)
return;
- auto R = llvm::make_unique<BugReport>(*BlockInCritSectionBugType,
- "A blocking function %s is called inside a critical section.", ErrNode);
+ std::string msg;
+ llvm::raw_string_ostream os(msg);
+ os << "Call to blocking function '" << Call.getCalleeIdentifier()->getName()
+ << "' inside of critical section";
+ auto R = llvm::make_unique<BugReport>(*BlockInCritSectionBugType, os.str(), ErrNode);
R->addRange(Call.getSourceRange());
R->markInteresting(BlockDescSym);
C.emitReport(std::move(R));
OpenPOWER on IntegriCloud