blob: 6c6901f412633fd1d70e99b0828e7c3e01fb97bd [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 Kyrtzidis983326f2011-02-23 01:05:36 +000016#include "clang/StaticAnalyzer/Core/CheckerV2.h"
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +000017#include "clang/StaticAnalyzer/Core/CheckerManager.h"
Argyrios Kyrtzidis983326f2011-02-23 01:05:36 +000018#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000019#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
20#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
Ted Kremenekac9bea82009-11-12 06:17:47 +000021#include "llvm/ADT/ImmutableSet.h"
22
23using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000024using namespace ento;
Ted Kremenekac9bea82009-11-12 06:17:47 +000025
26namespace {
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000027class PthreadLockChecker
Argyrios Kyrtzidis983326f2011-02-23 01:05:36 +000028 : public CheckerV2< check::PostStmt<CallExpr> > {
Ted Kremenekac9bea82009-11-12 06:17:47 +000029public:
Argyrios Kyrtzidis983326f2011-02-23 01:05:36 +000030 void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
Ted Kremenekac9bea82009-11-12 06:17:47 +000031
32 void AcquireLock(CheckerContext &C, const CallExpr *CE,
Argyrios Kyrtzidis983326f2011-02-23 01:05:36 +000033 SVal lock, bool isTryLock) const;
Ted Kremenekac9bea82009-11-12 06:17:47 +000034
35 void ReleaseLock(CheckerContext &C, const CallExpr *CE,
Argyrios Kyrtzidis983326f2011-02-23 01:05:36 +000036 SVal lock) const;
Ted Kremenekac9bea82009-11-12 06:17:47 +000037
38};
39} // end anonymous namespace
40
41// GDM Entry for tracking lock state.
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000042namespace { class LockSet {}; }
Ted Kremenekac9bea82009-11-12 06:17:47 +000043namespace clang {
Ted Kremenek9ef65372010-12-23 07:20:52 +000044namespace ento {
Ted Kremenekac9bea82009-11-12 06:17:47 +000045template <> struct GRStateTrait<LockSet> :
46 public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
Argyrios Kyrtzidis983326f2011-02-23 01:05:36 +000047 static void* GDMIndex() { static int x = 0; return &x; }
Ted Kremenekac9bea82009-11-12 06:17:47 +000048};
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +000049} // end GR namespace
Ted Kremenekac9bea82009-11-12 06:17:47 +000050} // end clang namespace
51
Ted Kremenekac9bea82009-11-12 06:17:47 +000052
Argyrios Kyrtzidis983326f2011-02-23 01:05:36 +000053void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
54 CheckerContext &C) const {
Ted Kremenekac9bea82009-11-12 06:17:47 +000055 const GRState *state = C.getState();
56 const Expr *Callee = CE->getCallee();
Ted Kremenekeb1c7a02009-11-25 01:32:22 +000057 const FunctionTextRegion *R =
Ted Kremenek13976632010-02-08 16:18:51 +000058 dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
Ted Kremenekac9bea82009-11-12 06:17:47 +000059
60 if (!R)
61 return;
62
Douglas Gregor90d26a42010-11-01 23:16:05 +000063 IdentifierInfo *II = R->getDecl()->getIdentifier();
64 if (!II) // if no identifier, not a simple C function
65 return;
66 llvm::StringRef FName = II->getName();
Ted Kremenekac9bea82009-11-12 06:17:47 +000067
Ted Kremenekfe37d042009-11-12 06:26:58 +000068 if (FName == "pthread_mutex_lock") {
69 if (CE->getNumArgs() != 1)
70 return;
Ted Kremenek13976632010-02-08 16:18:51 +000071 AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
Ted Kremenekfe37d042009-11-12 06:26:58 +000072 }
73 else if (FName == "pthread_mutex_trylock") {
74 if (CE->getNumArgs() != 1)
75 return;
Ted Kremenek13976632010-02-08 16:18:51 +000076 AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
Ted Kremenekfe37d042009-11-12 06:26:58 +000077 }
78 else if (FName == "pthread_mutex_unlock") {
Ted Kremenekac9bea82009-11-12 06:17:47 +000079 if (CE->getNumArgs() != 1)
80 return;
Ted Kremenek13976632010-02-08 16:18:51 +000081 ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
Ted Kremenekac9bea82009-11-12 06:17:47 +000082 }
83}
84
85void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
Argyrios Kyrtzidis983326f2011-02-23 01:05:36 +000086 SVal lock, bool isTryLock) const {
Ted Kremenekac9bea82009-11-12 06:17:47 +000087
88 const MemRegion *lockR = lock.getAsRegion();
89 if (!lockR)
90 return;
91
92 const GRState *state = C.getState();
93
Ted Kremenek13976632010-02-08 16:18:51 +000094 SVal X = state->getSVal(CE);
Ted Kremenekac9bea82009-11-12 06:17:47 +000095 if (X.isUnknownOrUndef())
96 return;
97
98 DefinedSVal retVal = cast<DefinedSVal>(X);
99 const GRState *lockSucc = state;
100
101 if (isTryLock) {
102 // Bifurcate the state, and allow a mode where the lock acquisition fails.
103 const GRState *lockFail;
Ted Kremenek28f47b92010-12-01 22:16:56 +0000104 llvm::tie(lockFail, lockSucc) = state->assume(retVal);
Ted Kremenekac9bea82009-11-12 06:17:47 +0000105 assert(lockFail && lockSucc);
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000106 C.addTransition(C.generateNode(CE, lockFail));
Ted Kremenekac9bea82009-11-12 06:17:47 +0000107 }
108 else {
109 // Assume that the return value was 0.
Ted Kremenek28f47b92010-12-01 22:16:56 +0000110 lockSucc = state->assume(retVal, false);
Ted Kremenekac9bea82009-11-12 06:17:47 +0000111 assert(lockSucc);
112 }
113
114 // Record that the lock was acquired.
115 lockSucc = lockSucc->add<LockSet>(lockR);
116
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000117 C.addTransition(lockSucc != state ? C.generateNode(CE, lockSucc) :
Ted Kremenekac9bea82009-11-12 06:17:47 +0000118 C.getPredecessor());
119}
120
121void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
Argyrios Kyrtzidis983326f2011-02-23 01:05:36 +0000122 SVal lock) const {
Ted Kremenekac9bea82009-11-12 06:17:47 +0000123
124 const MemRegion *lockR = lock.getAsRegion();
125 if (!lockR)
126 return;
127
128 const GRState *state = C.getState();
129
130 // Record that the lock was released.
131 // FIXME: Handle unlocking locks that were never acquired. This may
132 // require IPA for wrappers.
133 const GRState *unlockState = state->remove<LockSet>(lockR);
134
135 if (state == unlockState)
136 return;
137
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000138 C.addTransition(C.generateNode(CE, unlockState));
Ted Kremenekac9bea82009-11-12 06:17:47 +0000139}
Argyrios Kyrtzidis983326f2011-02-23 01:05:36 +0000140
141void ento::registerPthreadLockChecker(CheckerManager &mgr) {
142 mgr.registerChecker<PthreadLockChecker>();
143}