Author: xazax Date: Fri Mar 10 08:50:12 2017 New Revision: 297461 URL: http://llvm.org/viewvc/llvm-project?rev=297461&view=rev Log: [analyzer] Extend block in critical section check with C11 and Pthread APIs.
Patch by Zoltan Daniel Torok! Differential Revision: https://reviews.llvm.org/D29567 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp cfe/trunk/test/Analysis/block-in-critical-section.cpp cfe/trunk/www/analyzer/alpha_checks.html Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp?rev=297461&r1=297460&r2=297461&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp Fri Mar 10 08:50:12 2017 @@ -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 : pu 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(MutexCo 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::repo 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)); Modified: cfe/trunk/test/Analysis/block-in-critical-section.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/block-in-critical-section.cpp?rev=297461&r1=297460&r2=297461&view=diff ============================================================================== --- cfe/trunk/test/Analysis/block-in-critical-section.cpp (original) +++ cfe/trunk/test/Analysis/block-in-critical-section.cpp Fri Mar 10 08:50:12 2017 @@ -9,29 +9,91 @@ struct mutex { }; } -void testBlockInCriticalSection() { +void getc() {} +void fgets() {} +void read() {} +void recv() {} + +void pthread_mutex_lock() {} +void pthread_mutex_trylock() {} +void pthread_mutex_unlock() {} + +void mtx_lock() {} +void mtx_timedlock() {} +void mtx_trylock() {} +void mtx_unlock() {} + +void testBlockInCriticalSectionWithStdMutex() { std::mutex m; m.lock(); - sleep(3); // expected-warning {{A blocking function %s is called inside a critical section}} + sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} + getc(); // expected-warning {{Call to blocking function 'getc' inside of critical section}} + fgets(); // expected-warning {{Call to blocking function 'fgets' inside of critical section}} + read(); // expected-warning {{Call to blocking function 'read' inside of critical section}} + recv(); // expected-warning {{Call to blocking function 'recv' inside of critical section}} m.unlock(); } +void testBlockInCriticalSectionWithPthreadMutex() { + pthread_mutex_lock(); + sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} + getc(); // expected-warning {{Call to blocking function 'getc' inside of critical section}} + fgets(); // expected-warning {{Call to blocking function 'fgets' inside of critical section}} + read(); // expected-warning {{Call to blocking function 'read' inside of critical section}} + recv(); // expected-warning {{Call to blocking function 'recv' inside of critical section}} + pthread_mutex_unlock(); + + pthread_mutex_trylock(); + sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} + getc(); // expected-warning {{Call to blocking function 'getc' inside of critical section}} + fgets(); // expected-warning {{Call to blocking function 'fgets' inside of critical section}} + read(); // expected-warning {{Call to blocking function 'read' inside of critical section}} + recv(); // expected-warning {{Call to blocking function 'recv' inside of critical section}} + pthread_mutex_unlock(); +} + +void testBlockInCriticalSectionC11Locks() { + mtx_lock(); + sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} + getc(); // expected-warning {{Call to blocking function 'getc' inside of critical section}} + fgets(); // expected-warning {{Call to blocking function 'fgets' inside of critical section}} + read(); // expected-warning {{Call to blocking function 'read' inside of critical section}} + recv(); // expected-warning {{Call to blocking function 'recv' inside of critical section}} + mtx_unlock(); + + mtx_timedlock(); + sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} + getc(); // expected-warning {{Call to blocking function 'getc' inside of critical section}} + fgets(); // expected-warning {{Call to blocking function 'fgets' inside of critical section}} + read(); // expected-warning {{Call to blocking function 'read' inside of critical section}} + recv(); // expected-warning {{Call to blocking function 'recv' inside of critical section}} + mtx_unlock(); + + mtx_trylock(); + sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} + getc(); // expected-warning {{Call to blocking function 'getc' inside of critical section}} + fgets(); // expected-warning {{Call to blocking function 'fgets' inside of critical section}} + read(); // expected-warning {{Call to blocking function 'read' inside of critical section}} + recv(); // expected-warning {{Call to blocking function 'recv' inside of critical section}} + mtx_unlock(); +} + void testBlockInCriticalSectionWithNestedMutexes() { std::mutex m, n, k; m.lock(); n.lock(); k.lock(); - sleep(3); // expected-warning {{A blocking function %s is called inside a critical section}} + sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} k.unlock(); - sleep(5); // expected-warning {{A blocking function %s is called inside a critical section}} + sleep(5); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} n.unlock(); - sleep(3); // expected-warning {{A blocking function %s is called inside a critical section}} + sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} m.unlock(); sleep(3); // no-warning } void f() { - sleep(1000); // expected-warning {{A blocking function %s is called inside a critical section}} + sleep(1000); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} } void testBlockInCriticalSectionInterProcedural() { @@ -46,5 +108,5 @@ void testBlockInCriticalSectionUnexpecte m.unlock(); sleep(1); // no-warning m.lock(); - sleep(1); // expected-warning {{A blocking function %s is called inside a critical section}} + sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} } Modified: cfe/trunk/www/analyzer/alpha_checks.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/analyzer/alpha_checks.html?rev=297461&r1=297460&r2=297461&view=diff ============================================================================== --- cfe/trunk/www/analyzer/alpha_checks.html (original) +++ cfe/trunk/www/analyzer/alpha_checks.html Fri Mar 10 08:50:12 2017 @@ -910,6 +910,30 @@ void test(char *y) { } </pre></div></div></td></tr> + +<tr><td><div class="namedescr expandable"><span class="name"> +alpha.unix.cstring.BlockInCriticalSection</span><span class="lang"> +(C)</span><div class="descr"> +Check for calls to blocking functions inside a critical section; applies +to:<div class=functions> +lock, unlock<br> +sleep<br> +getc<br> +fgets<br> +read<br> +recv<br> +pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock<br> +mtx_lock, mtx_timedlock, mtx_trylock, mtx_unlock<br> +</div></div></div></td> +<td><div class="exampleContainer expandable"> +<div class="example"><pre> +void testBlockInCriticalSection() { + std::mutex m; + m.lock(); + sleep(3); // warn + m.unlock(); +} +</pre></div></div></td></tr> </tbody></table> </div> <!-- page --> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits