From 829c6bc04a6fd39845ada8498b149fdcc99139db Mon Sep 17 00:00:00 2001 From: Gabor Horvath Date: Fri, 10 Mar 2017 14:50:12 +0000 Subject: [PATCH] [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 --- .../BlockInCriticalSectionChecker.cpp | 70 +++++++++++++---- .../Analysis/block-in-critical-section.cpp | 76 +++++++++++++++++-- clang/www/analyzer/alpha_checks.html | 24 ++++++ 3 files changed, 150 insertions(+), 20 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp index 082a4873217b..d19630eeef77 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp @@ -29,7 +29,9 @@ namespace { class BlockInCriticalSectionChecker : public Checker { - 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 BlockInCritSectionBugType; @@ -40,6 +42,10 @@ class BlockInCriticalSectionChecker : public Checkerget(); - if (Call.isCalled(UnlockFn) && mutexCount > 0) { + if (isUnlockFunction(Call) && mutexCount > 0) { State = State->set(--mutexCount); C.addTransition(State); - } else if (Call.isCalled(LockFn)) { + } else if (isLockFunction(Call)) { State = State->set(++mutexCount); C.addTransition(State); } else if (mutexCount > 0) { @@ -97,8 +138,11 @@ void BlockInCriticalSectionChecker::reportBlockInCritSection( if (!ErrNode) return; - auto R = llvm::make_unique(*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(*BlockInCritSectionBugType, os.str(), ErrNode); R->addRange(Call.getSourceRange()); R->markInteresting(BlockDescSym); C.emitReport(std::move(R)); diff --git a/clang/test/Analysis/block-in-critical-section.cpp b/clang/test/Analysis/block-in-critical-section.cpp index c940ad563f7c..c65cc612cf73 100644 --- a/clang/test/Analysis/block-in-critical-section.cpp +++ b/clang/test/Analysis/block-in-critical-section.cpp @@ -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 testBlockInCriticalSectionUnexpectedUnlock() { 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}} } diff --git a/clang/www/analyzer/alpha_checks.html b/clang/www/analyzer/alpha_checks.html index 0312d16aced4..ce9392b9960c 100644 --- a/clang/www/analyzer/alpha_checks.html +++ b/clang/www/analyzer/alpha_checks.html @@ -910,6 +910,30 @@ void test(char *y) { } + + +