blob: 1080e16027da62680d719444566eb31483bdd59b [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
11// this shouldn't be registered with GRExprEngineInternalChecks.
12//
13//===----------------------------------------------------------------------===//
14
Ted Kremenek1309f9a2010-01-25 04:41:41 +000015#include "clang/Checker/PathSensitive/CheckerVisitor.h"
Ted Kremenek6b676302010-01-25 17:10:22 +000016#include "clang/Checker/BugReporter/BugReporter.h"
Ted Kremenek1309f9a2010-01-25 04:41:41 +000017#include "clang/Checker/PathSensitive/GRStateTrait.h"
Ted Kremenekac9bea82009-11-12 06:17:47 +000018#include "GRExprEngineExperimentalChecks.h"
19#include "llvm/ADT/ImmutableSet.h"
20
21using namespace clang;
22
23namespace {
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000024class PthreadLockChecker
Ted Kremenekac9bea82009-11-12 06:17:47 +000025 : public CheckerVisitor<PthreadLockChecker> {
26 BugType *BT;
27public:
28 PthreadLockChecker() : BT(0) {}
29 static void *getTag() {
30 static int x = 0;
31 return &x;
32 }
Ted Kremenekac9bea82009-11-12 06:17:47 +000033 void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
34
35 void AcquireLock(CheckerContext &C, const CallExpr *CE,
36 SVal lock, bool isTryLock);
37
38 void ReleaseLock(CheckerContext &C, const CallExpr *CE,
39 SVal lock);
40
41};
42} // end anonymous namespace
43
44// GDM Entry for tracking lock state.
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000045namespace { class LockSet {}; }
Ted Kremenekac9bea82009-11-12 06:17:47 +000046namespace clang {
47template <> struct GRStateTrait<LockSet> :
48 public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
49 static void* GDMIndex() { return PthreadLockChecker::getTag(); }
50};
51} // end clang namespace
52
53void clang::RegisterPthreadLockChecker(GRExprEngine &Eng) {
54 Eng.registerCheck(new PthreadLockChecker());
55}
56
Ted Kremenekac9bea82009-11-12 06:17:47 +000057
58void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
59 const CallExpr *CE) {
60 const GRState *state = C.getState();
61 const Expr *Callee = CE->getCallee();
Ted Kremenekeb1c7a02009-11-25 01:32:22 +000062 const FunctionTextRegion *R =
Ted Kremenek13976632010-02-08 16:18:51 +000063 dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
Ted Kremenekac9bea82009-11-12 06:17:47 +000064
65 if (!R)
66 return;
67
Douglas Gregor90d26a42010-11-01 23:16:05 +000068 IdentifierInfo *II = R->getDecl()->getIdentifier();
69 if (!II) // if no identifier, not a simple C function
70 return;
71 llvm::StringRef FName = II->getName();
Ted Kremenekac9bea82009-11-12 06:17:47 +000072
Ted Kremenekfe37d042009-11-12 06:26:58 +000073 if (FName == "pthread_mutex_lock") {
74 if (CE->getNumArgs() != 1)
75 return;
Ted Kremenek13976632010-02-08 16:18:51 +000076 AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
Ted Kremenekfe37d042009-11-12 06:26:58 +000077 }
78 else if (FName == "pthread_mutex_trylock") {
79 if (CE->getNumArgs() != 1)
80 return;
Ted Kremenek13976632010-02-08 16:18:51 +000081 AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
Ted Kremenekfe37d042009-11-12 06:26:58 +000082 }
83 else if (FName == "pthread_mutex_unlock") {
Ted Kremenekac9bea82009-11-12 06:17:47 +000084 if (CE->getNumArgs() != 1)
85 return;
Ted Kremenek13976632010-02-08 16:18:51 +000086 ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
Ted Kremenekac9bea82009-11-12 06:17:47 +000087 }
88}
89
90void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
91 SVal lock, bool isTryLock) {
92
93 const MemRegion *lockR = lock.getAsRegion();
94 if (!lockR)
95 return;
96
97 const GRState *state = C.getState();
98
Ted Kremenek13976632010-02-08 16:18:51 +000099 SVal X = state->getSVal(CE);
Ted Kremenekac9bea82009-11-12 06:17:47 +0000100 if (X.isUnknownOrUndef())
101 return;
102
103 DefinedSVal retVal = cast<DefinedSVal>(X);
104 const GRState *lockSucc = state;
105
106 if (isTryLock) {
107 // Bifurcate the state, and allow a mode where the lock acquisition fails.
108 const GRState *lockFail;
Ted Kremenek28f47b92010-12-01 22:16:56 +0000109 llvm::tie(lockFail, lockSucc) = state->assume(retVal);
Ted Kremenekac9bea82009-11-12 06:17:47 +0000110 assert(lockFail && lockSucc);
111 C.addTransition(C.GenerateNode(CE, lockFail));
112 }
113 else {
114 // Assume that the return value was 0.
Ted Kremenek28f47b92010-12-01 22:16:56 +0000115 lockSucc = state->assume(retVal, false);
Ted Kremenekac9bea82009-11-12 06:17:47 +0000116 assert(lockSucc);
117 }
118
119 // Record that the lock was acquired.
120 lockSucc = lockSucc->add<LockSet>(lockR);
121
122 C.addTransition(lockSucc != state ? C.GenerateNode(CE, lockSucc) :
123 C.getPredecessor());
124}
125
126void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
127 SVal lock) {
128
129 const MemRegion *lockR = lock.getAsRegion();
130 if (!lockR)
131 return;
132
133 const GRState *state = C.getState();
134
135 // Record that the lock was released.
136 // FIXME: Handle unlocking locks that were never acquired. This may
137 // require IPA for wrappers.
138 const GRState *unlockState = state->remove<LockSet>(lockR);
139
140 if (state == unlockState)
141 return;
142
143 C.addTransition(C.GenerateNode(CE, unlockState));
144}