blob: 34c095f42e08469abbea50372682a53189f96939 [file] [log] [blame]
Ted Kremenekac9bea82009-11-12 06:17:47 +00001//===--- PthreadLockChecker.h - Undefined arguments checker ----*- 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// This defines PthreadLockChecker, a simple lock -> unlock checker. Eventually
Argyrios Kyrtzidisd2592a32010-12-22 18:53:44 +000011// this shouldn't be registered with ExprEngineInternalChecks.
Ted Kremenekac9bea82009-11-12 06:17:47 +000012//
13//===----------------------------------------------------------------------===//
14
Argyrios Kyrtzidisa0decc92011-02-15 21:25:03 +000015#include "ClangSACheckers.h"
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +000016#include "clang/StaticAnalyzer/Core/CheckerManager.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000017#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
18#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
Ted Kremenekac9bea82009-11-12 06:17:47 +000020#include "llvm/ADT/ImmutableSet.h"
21
22using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000023using namespace ento;
Ted Kremenekac9bea82009-11-12 06:17:47 +000024
25namespace {
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000026class PthreadLockChecker
Ted Kremenekac9bea82009-11-12 06:17:47 +000027 : public CheckerVisitor<PthreadLockChecker> {
28 BugType *BT;
29public:
30 PthreadLockChecker() : BT(0) {}
31 static void *getTag() {
32 static int x = 0;
33 return &x;
34 }
Ted Kremenekac9bea82009-11-12 06:17:47 +000035 void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
36
37 void AcquireLock(CheckerContext &C, const CallExpr *CE,
38 SVal lock, bool isTryLock);
39
40 void ReleaseLock(CheckerContext &C, const CallExpr *CE,
41 SVal lock);
42
43};
44} // end anonymous namespace
45
46// GDM Entry for tracking lock state.
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000047namespace { class LockSet {}; }
Ted Kremenekac9bea82009-11-12 06:17:47 +000048namespace clang {
Ted Kremenek9ef65372010-12-23 07:20:52 +000049namespace ento {
Ted Kremenekac9bea82009-11-12 06:17:47 +000050template <> struct GRStateTrait<LockSet> :
51 public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
52 static void* GDMIndex() { return PthreadLockChecker::getTag(); }
53};
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +000054} // end GR namespace
Ted Kremenekac9bea82009-11-12 06:17:47 +000055} // end clang namespace
56
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +000057static void RegisterPthreadLockChecker(ExprEngine &Eng) {
Ted Kremenekac9bea82009-11-12 06:17:47 +000058 Eng.registerCheck(new PthreadLockChecker());
59}
60
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +000061void ento::registerPthreadLockChecker(CheckerManager &mgr) {
62 mgr.addCheckerRegisterFunction(RegisterPthreadLockChecker);
63}
64
Ted Kremenekac9bea82009-11-12 06:17:47 +000065
66void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
67 const CallExpr *CE) {
68 const GRState *state = C.getState();
69 const Expr *Callee = CE->getCallee();
Ted Kremenekeb1c7a02009-11-25 01:32:22 +000070 const FunctionTextRegion *R =
Ted Kremenek13976632010-02-08 16:18:51 +000071 dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
Ted Kremenekac9bea82009-11-12 06:17:47 +000072
73 if (!R)
74 return;
75
Douglas Gregor90d26a42010-11-01 23:16:05 +000076 IdentifierInfo *II = R->getDecl()->getIdentifier();
77 if (!II) // if no identifier, not a simple C function
78 return;
79 llvm::StringRef FName = II->getName();
Ted Kremenekac9bea82009-11-12 06:17:47 +000080
Ted Kremenekfe37d042009-11-12 06:26:58 +000081 if (FName == "pthread_mutex_lock") {
82 if (CE->getNumArgs() != 1)
83 return;
Ted Kremenek13976632010-02-08 16:18:51 +000084 AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
Ted Kremenekfe37d042009-11-12 06:26:58 +000085 }
86 else if (FName == "pthread_mutex_trylock") {
87 if (CE->getNumArgs() != 1)
88 return;
Ted Kremenek13976632010-02-08 16:18:51 +000089 AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
Ted Kremenekfe37d042009-11-12 06:26:58 +000090 }
91 else if (FName == "pthread_mutex_unlock") {
Ted Kremenekac9bea82009-11-12 06:17:47 +000092 if (CE->getNumArgs() != 1)
93 return;
Ted Kremenek13976632010-02-08 16:18:51 +000094 ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
Ted Kremenekac9bea82009-11-12 06:17:47 +000095 }
96}
97
98void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
99 SVal lock, bool isTryLock) {
100
101 const MemRegion *lockR = lock.getAsRegion();
102 if (!lockR)
103 return;
104
105 const GRState *state = C.getState();
106
Ted Kremenek13976632010-02-08 16:18:51 +0000107 SVal X = state->getSVal(CE);
Ted Kremenekac9bea82009-11-12 06:17:47 +0000108 if (X.isUnknownOrUndef())
109 return;
110
111 DefinedSVal retVal = cast<DefinedSVal>(X);
112 const GRState *lockSucc = state;
113
114 if (isTryLock) {
115 // Bifurcate the state, and allow a mode where the lock acquisition fails.
116 const GRState *lockFail;
Ted Kremenek28f47b92010-12-01 22:16:56 +0000117 llvm::tie(lockFail, lockSucc) = state->assume(retVal);
Ted Kremenekac9bea82009-11-12 06:17:47 +0000118 assert(lockFail && lockSucc);
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000119 C.addTransition(C.generateNode(CE, lockFail));
Ted Kremenekac9bea82009-11-12 06:17:47 +0000120 }
121 else {
122 // Assume that the return value was 0.
Ted Kremenek28f47b92010-12-01 22:16:56 +0000123 lockSucc = state->assume(retVal, false);
Ted Kremenekac9bea82009-11-12 06:17:47 +0000124 assert(lockSucc);
125 }
126
127 // Record that the lock was acquired.
128 lockSucc = lockSucc->add<LockSet>(lockR);
129
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000130 C.addTransition(lockSucc != state ? C.generateNode(CE, lockSucc) :
Ted Kremenekac9bea82009-11-12 06:17:47 +0000131 C.getPredecessor());
132}
133
134void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
135 SVal lock) {
136
137 const MemRegion *lockR = lock.getAsRegion();
138 if (!lockR)
139 return;
140
141 const GRState *state = C.getState();
142
143 // Record that the lock was released.
144 // FIXME: Handle unlocking locks that were never acquired. This may
145 // require IPA for wrappers.
146 const GRState *unlockState = state->remove<LockSet>(lockR);
147
148 if (state == unlockState)
149 return;
150
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000151 C.addTransition(C.generateNode(CE, unlockState));
Ted Kremenekac9bea82009-11-12 06:17:47 +0000152}