blob: ae58b78fb8a11e897d1b76627fec1c7da543b7de [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 Kyrtzidis98cabba2010-12-22 18:51:49 +000015#include "clang/GR/PathSensitive/CheckerVisitor.h"
16#include "clang/GR/BugReporter/BugReporter.h"
17#include "clang/GR/PathSensitive/GRStateTrait.h"
Argyrios Kyrtzidisd2592a32010-12-22 18:53:44 +000018#include "ExprEngineExperimentalChecks.h"
Ted Kremenekac9bea82009-11-12 06:17:47 +000019#include "llvm/ADT/ImmutableSet.h"
20
21using namespace clang;
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +000022using namespace GR;
Ted Kremenekac9bea82009-11-12 06:17:47 +000023
24namespace {
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000025class PthreadLockChecker
Ted Kremenekac9bea82009-11-12 06:17:47 +000026 : public CheckerVisitor<PthreadLockChecker> {
27 BugType *BT;
28public:
29 PthreadLockChecker() : BT(0) {}
30 static void *getTag() {
31 static int x = 0;
32 return &x;
33 }
Ted Kremenekac9bea82009-11-12 06:17:47 +000034 void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
35
36 void AcquireLock(CheckerContext &C, const CallExpr *CE,
37 SVal lock, bool isTryLock);
38
39 void ReleaseLock(CheckerContext &C, const CallExpr *CE,
40 SVal lock);
41
42};
43} // end anonymous namespace
44
45// GDM Entry for tracking lock state.
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000046namespace { class LockSet {}; }
Ted Kremenekac9bea82009-11-12 06:17:47 +000047namespace clang {
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +000048namespace GR {
Ted Kremenekac9bea82009-11-12 06:17:47 +000049template <> struct GRStateTrait<LockSet> :
50 public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
51 static void* GDMIndex() { return PthreadLockChecker::getTag(); }
52};
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +000053} // end GR namespace
Ted Kremenekac9bea82009-11-12 06:17:47 +000054} // end clang namespace
55
Argyrios Kyrtzidisd2592a32010-12-22 18:53:44 +000056void GR::RegisterPthreadLockChecker(ExprEngine &Eng) {
Ted Kremenekac9bea82009-11-12 06:17:47 +000057 Eng.registerCheck(new PthreadLockChecker());
58}
59
Ted Kremenekac9bea82009-11-12 06:17:47 +000060
61void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
62 const CallExpr *CE) {
63 const GRState *state = C.getState();
64 const Expr *Callee = CE->getCallee();
Ted Kremenekeb1c7a02009-11-25 01:32:22 +000065 const FunctionTextRegion *R =
Ted Kremenek13976632010-02-08 16:18:51 +000066 dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
Ted Kremenekac9bea82009-11-12 06:17:47 +000067
68 if (!R)
69 return;
70
Douglas Gregor90d26a42010-11-01 23:16:05 +000071 IdentifierInfo *II = R->getDecl()->getIdentifier();
72 if (!II) // if no identifier, not a simple C function
73 return;
74 llvm::StringRef FName = II->getName();
Ted Kremenekac9bea82009-11-12 06:17:47 +000075
Ted Kremenekfe37d042009-11-12 06:26:58 +000076 if (FName == "pthread_mutex_lock") {
77 if (CE->getNumArgs() != 1)
78 return;
Ted Kremenek13976632010-02-08 16:18:51 +000079 AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
Ted Kremenekfe37d042009-11-12 06:26:58 +000080 }
81 else if (FName == "pthread_mutex_trylock") {
82 if (CE->getNumArgs() != 1)
83 return;
Ted Kremenek13976632010-02-08 16:18:51 +000084 AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
Ted Kremenekfe37d042009-11-12 06:26:58 +000085 }
86 else if (FName == "pthread_mutex_unlock") {
Ted Kremenekac9bea82009-11-12 06:17:47 +000087 if (CE->getNumArgs() != 1)
88 return;
Ted Kremenek13976632010-02-08 16:18:51 +000089 ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
Ted Kremenekac9bea82009-11-12 06:17:47 +000090 }
91}
92
93void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
94 SVal lock, bool isTryLock) {
95
96 const MemRegion *lockR = lock.getAsRegion();
97 if (!lockR)
98 return;
99
100 const GRState *state = C.getState();
101
Ted Kremenek13976632010-02-08 16:18:51 +0000102 SVal X = state->getSVal(CE);
Ted Kremenekac9bea82009-11-12 06:17:47 +0000103 if (X.isUnknownOrUndef())
104 return;
105
106 DefinedSVal retVal = cast<DefinedSVal>(X);
107 const GRState *lockSucc = state;
108
109 if (isTryLock) {
110 // Bifurcate the state, and allow a mode where the lock acquisition fails.
111 const GRState *lockFail;
Ted Kremenek28f47b92010-12-01 22:16:56 +0000112 llvm::tie(lockFail, lockSucc) = state->assume(retVal);
Ted Kremenekac9bea82009-11-12 06:17:47 +0000113 assert(lockFail && lockSucc);
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000114 C.addTransition(C.generateNode(CE, lockFail));
Ted Kremenekac9bea82009-11-12 06:17:47 +0000115 }
116 else {
117 // Assume that the return value was 0.
Ted Kremenek28f47b92010-12-01 22:16:56 +0000118 lockSucc = state->assume(retVal, false);
Ted Kremenekac9bea82009-11-12 06:17:47 +0000119 assert(lockSucc);
120 }
121
122 // Record that the lock was acquired.
123 lockSucc = lockSucc->add<LockSet>(lockR);
124
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000125 C.addTransition(lockSucc != state ? C.generateNode(CE, lockSucc) :
Ted Kremenekac9bea82009-11-12 06:17:47 +0000126 C.getPredecessor());
127}
128
129void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
130 SVal lock) {
131
132 const MemRegion *lockR = lock.getAsRegion();
133 if (!lockR)
134 return;
135
136 const GRState *state = C.getState();
137
138 // Record that the lock was released.
139 // FIXME: Handle unlocking locks that were never acquired. This may
140 // require IPA for wrappers.
141 const GRState *unlockState = state->remove<LockSet>(lockR);
142
143 if (state == unlockState)
144 return;
145
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000146 C.addTransition(C.generateNode(CE, unlockState));
Ted Kremenekac9bea82009-11-12 06:17:47 +0000147}