]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / BlockInCriticalSectionChecker.cpp
1 //===-- BlockInCriticalSectionChecker.cpp -----------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Defines a checker for blocks in critical sections. This checker should find
11 // the calls to blocking functions (for example: sleep, getc, fgets, read,
12 // recv etc.) inside a critical section. When sleep(x) is called while a mutex
13 // is held, other threades cannot lock the same mutex. This might take some
14 // time, leading to bad performance or even deadlock.
15 //
16 //===----------------------------------------------------------------------===//
17
18 #include "ClangSACheckers.h"
19 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20 #include "clang/StaticAnalyzer/Core/Checker.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
23
24 using namespace clang;
25 using namespace ento;
26
27 namespace {
28
29 class BlockInCriticalSectionChecker : public Checker<check::PostCall,
30                                                      check::PreCall> {
31
32   CallDescription LockFn, UnlockFn, SleepFn, GetcFn, FgetsFn, ReadFn, RecvFn;
33
34   std::unique_ptr<BugType> BlockInCritSectionBugType;
35
36   void reportBlockInCritSection(SymbolRef FileDescSym,
37                                 const CallEvent &call,
38                                 CheckerContext &C) const;
39
40 public:
41   BlockInCriticalSectionChecker();
42
43   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
44
45   /// Process unlock.
46   /// Process lock.
47   /// Process blocking functions (sleep, getc, fgets, read, recv)
48   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
49
50 };
51
52 } // end anonymous namespace
53
54 REGISTER_TRAIT_WITH_PROGRAMSTATE(MutexCounter, unsigned)
55
56 BlockInCriticalSectionChecker::BlockInCriticalSectionChecker()
57     : LockFn("lock"), UnlockFn("unlock"), SleepFn("sleep"), GetcFn("getc"),
58       FgetsFn("fgets"), ReadFn("read"), RecvFn("recv") {
59   // Initialize the bug type.
60   BlockInCritSectionBugType.reset(
61       new BugType(this, "Call to blocking function in critical section",
62                         "Blocking Error"));
63 }
64
65 void BlockInCriticalSectionChecker::checkPreCall(const CallEvent &Call,
66                                                  CheckerContext &C) const {
67 }
68
69 void BlockInCriticalSectionChecker::checkPostCall(const CallEvent &Call,
70                                                   CheckerContext &C) const {
71   if (!Call.isCalled(LockFn)
72       && !Call.isCalled(SleepFn)
73       && !Call.isCalled(GetcFn)
74       && !Call.isCalled(FgetsFn)
75       && !Call.isCalled(ReadFn)
76       && !Call.isCalled(RecvFn)
77       && !Call.isCalled(UnlockFn))
78     return;
79
80   ProgramStateRef State = C.getState();
81   unsigned mutexCount = State->get<MutexCounter>();
82   if (Call.isCalled(UnlockFn) && mutexCount > 0) {
83     State = State->set<MutexCounter>(--mutexCount);
84     C.addTransition(State);
85   } else if (Call.isCalled(LockFn)) {
86     State = State->set<MutexCounter>(++mutexCount);
87     C.addTransition(State);
88   } else if (mutexCount > 0) {
89     SymbolRef BlockDesc = Call.getReturnValue().getAsSymbol();
90     reportBlockInCritSection(BlockDesc, Call, C);
91   }
92 }
93
94 void BlockInCriticalSectionChecker::reportBlockInCritSection(
95     SymbolRef BlockDescSym, const CallEvent &Call, CheckerContext &C) const {
96   ExplodedNode *ErrNode = C.generateNonFatalErrorNode();
97   if (!ErrNode)
98     return;
99
100   auto R = llvm::make_unique<BugReport>(*BlockInCritSectionBugType,
101       "A blocking function %s is called inside a critical section.", ErrNode);
102   R->addRange(Call.getSourceRange());
103   R->markInteresting(BlockDescSym);
104   C.emitReport(std::move(R));
105 }
106
107 void ento::registerBlockInCriticalSectionChecker(CheckerManager &mgr) {
108   mgr.registerChecker<BlockInCriticalSectionChecker>();
109 }