This revision was automatically updated to reflect the committed changes.
Closed by commit rL282011: [analyzer] Add a checker that detects blocks in
critical sections (authored by zaks).
Changed prior to commit:
https://reviews.llvm.org/D21506?vs=71375&id=71977#toc
Repository:
rL LLVM
https://reviews.llvm.org/D21506
Files:
cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
cfe/trunk/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
cfe/trunk/test/Analysis/block-in-critical-section.cpp
Index: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -436,6 +436,10 @@
HelpText<"Check for misuses of stream APIs">,
DescFile<"SimpleStreamChecker.cpp">;
+def BlockInCriticalSectionChecker : Checker<"BlockInCriticalSection">,
+ HelpText<"Check for calls to blocking functions inside a critical section">,
+ DescFile<"BlockInCriticalSectionChecker.cpp">;
+
} // end "alpha.unix"
let ParentPackage = CString in {
Index: cfe/trunk/test/Analysis/block-in-critical-section.cpp
===================================================================
--- cfe/trunk/test/Analysis/block-in-critical-section.cpp
+++ cfe/trunk/test/Analysis/block-in-critical-section.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.unix.BlockInCriticalSection -std=c++11 -verify %s
+
+void sleep(int x) {}
+
+namespace std {
+struct mutex {
+ void lock() {}
+ void unlock() {}
+};
+}
+
+void testBlockInCriticalSection() {
+ std::mutex m;
+ m.lock();
+ sleep(3); // expected-warning {{A blocking function %s is called inside a critical section}}
+ m.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}}
+ k.unlock();
+ sleep(5); // expected-warning {{A blocking function %s is called inside a critical section}}
+ n.unlock();
+ sleep(3); // expected-warning {{A blocking function %s is called inside a critical section}}
+ m.unlock();
+ sleep(3); // no-warning
+}
+
+void f() {
+ sleep(1000); // expected-warning {{A blocking function %s is called inside a critical section}}
+}
+
+void testBlockInCriticalSectionInterProcedural() {
+ std::mutex m;
+ m.lock();
+ f();
+ m.unlock();
+}
+
+void testBlockInCriticalSectionUnexpectedUnlock() {
+ std::mutex m;
+ m.unlock();
+ sleep(1); // no-warning
+ m.lock();
+ sleep(1); // expected-warning {{A blocking function %s is called inside a critical section}}
+}
Index: cfe/trunk/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
===================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
@@ -0,0 +1,109 @@
+//===-- BlockInCriticalSectionChecker.cpp -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a checker for blocks in critical sections. This checker should find
+// the calls to blocking functions (for example: sleep, getc, fgets, read,
+// recv etc.) inside a critical section. When sleep(x) is called while a mutex
+// is held, other threades cannot lock the same mutex. This might take some
+// time, leading to bad performance or even deadlock.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class BlockInCriticalSectionChecker : public Checker<check::PostCall,
+ check::PreCall> {
+
+ CallDescription LockFn, UnlockFn, SleepFn, GetcFn, FgetsFn, ReadFn, RecvFn;
+
+ std::unique_ptr<BugType> BlockInCritSectionBugType;
+
+ void reportBlockInCritSection(SymbolRef FileDescSym,
+ const CallEvent &call,
+ CheckerContext &C) const;
+
+public:
+ BlockInCriticalSectionChecker();
+
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+
+ /// Process unlock.
+ /// Process lock.
+ /// Process blocking functions (sleep, getc, fgets, read, recv)
+ void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+
+};
+
+} // end anonymous namespace
+
+REGISTER_TRAIT_WITH_PROGRAMSTATE(MutexCounter, unsigned)
+
+BlockInCriticalSectionChecker::BlockInCriticalSectionChecker()
+ : LockFn("lock"), UnlockFn("unlock"), SleepFn("sleep"), GetcFn("getc"),
+ FgetsFn("fgets"), ReadFn("read"), RecvFn("recv") {
+ // Initialize the bug type.
+ BlockInCritSectionBugType.reset(
+ new BugType(this, "Call to blocking function in critical section",
+ "Blocking Error"));
+}
+
+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))
+ return;
+
+ ProgramStateRef State = C.getState();
+ unsigned mutexCount = State->get<MutexCounter>();
+ if (Call.isCalled(UnlockFn) && mutexCount > 0) {
+ State = State->set<MutexCounter>(--mutexCount);
+ C.addTransition(State);
+ } else if (Call.isCalled(LockFn)) {
+ State = State->set<MutexCounter>(++mutexCount);
+ C.addTransition(State);
+ } else if (mutexCount > 0) {
+ SymbolRef BlockDesc = Call.getReturnValue().getAsSymbol();
+ reportBlockInCritSection(BlockDesc, Call, C);
+ }
+}
+
+void BlockInCriticalSectionChecker::reportBlockInCritSection(
+ SymbolRef BlockDescSym, const CallEvent &Call, CheckerContext &C) const {
+ ExplodedNode *ErrNode = C.generateNonFatalErrorNode();
+ if (!ErrNode)
+ return;
+
+ auto R = llvm::make_unique<BugReport>(*BlockInCritSectionBugType,
+ "A blocking function %s is called inside a critical section.", ErrNode);
+ R->addRange(Call.getSourceRange());
+ R->markInteresting(BlockDescSym);
+ C.emitReport(std::move(R));
+}
+
+void ento::registerBlockInCriticalSectionChecker(CheckerManager &mgr) {
+ mgr.registerChecker<BlockInCriticalSectionChecker>();
+}
Index: cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -9,6 +9,7 @@
ArrayBoundChecker.cpp
ArrayBoundCheckerV2.cpp
BasicObjCFoundationChecks.cpp
+ BlockInCriticalSectionChecker.cpp
BoolAssignmentChecker.cpp
BuiltinFunctionChecker.cpp
CStringChecker.cpp
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits