blob: 74e266c3edfcf02e53dbc57a72a764c8f7740896 [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
68 llvm::StringRef FName = R->getDecl()->getName();
69
Ted Kremenekfe37d042009-11-12 06:26:58 +000070 if (FName == "pthread_mutex_lock") {
71 if (CE->getNumArgs() != 1)
72 return;
Ted Kremenek13976632010-02-08 16:18:51 +000073 AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
Ted Kremenekfe37d042009-11-12 06:26:58 +000074 }
75 else if (FName == "pthread_mutex_trylock") {
76 if (CE->getNumArgs() != 1)
77 return;
Ted Kremenek13976632010-02-08 16:18:51 +000078 AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
Ted Kremenekfe37d042009-11-12 06:26:58 +000079 }
80 else if (FName == "pthread_mutex_unlock") {
Ted Kremenekac9bea82009-11-12 06:17:47 +000081 if (CE->getNumArgs() != 1)
82 return;
Ted Kremenek13976632010-02-08 16:18:51 +000083 ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
Ted Kremenekac9bea82009-11-12 06:17:47 +000084 }
85}
86
87void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
88 SVal lock, bool isTryLock) {
89
90 const MemRegion *lockR = lock.getAsRegion();
91 if (!lockR)
92 return;
93
94 const GRState *state = C.getState();
95
Ted Kremenek13976632010-02-08 16:18:51 +000096 SVal X = state->getSVal(CE);
Ted Kremenekac9bea82009-11-12 06:17:47 +000097 if (X.isUnknownOrUndef())
98 return;
99
100 DefinedSVal retVal = cast<DefinedSVal>(X);
101 const GRState *lockSucc = state;
102
103 if (isTryLock) {
104 // Bifurcate the state, and allow a mode where the lock acquisition fails.
105 const GRState *lockFail;
106 llvm::tie(lockFail, lockSucc) = state->Assume(retVal);
107 assert(lockFail && lockSucc);
108 C.addTransition(C.GenerateNode(CE, lockFail));
109 }
110 else {
111 // Assume that the return value was 0.
112 lockSucc = state->Assume(retVal, false);
113 assert(lockSucc);
114 }
115
116 // Record that the lock was acquired.
117 lockSucc = lockSucc->add<LockSet>(lockR);
118
119 C.addTransition(lockSucc != state ? C.GenerateNode(CE, lockSucc) :
120 C.getPredecessor());
121}
122
123void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
124 SVal lock) {
125
126 const MemRegion *lockR = lock.getAsRegion();
127 if (!lockR)
128 return;
129
130 const GRState *state = C.getState();
131
132 // Record that the lock was released.
133 // FIXME: Handle unlocking locks that were never acquired. This may
134 // require IPA for wrappers.
135 const GRState *unlockState = state->remove<LockSet>(lockR);
136
137 if (state == unlockState)
138 return;
139
140 C.addTransition(C.GenerateNode(CE, unlockState));
141}