1 //===--- PthreadLockChecker.h - Undefined arguments checker ----*- C++ -*--===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This defines PthreadLockChecker, a simple lock -> unlock checker. Eventually
11 // this shouldn't be registered with GRExprEngineInternalChecks.
13 //===----------------------------------------------------------------------===//
15 #include "clang/Checker/PathSensitive/CheckerVisitor.h"
16 #include "clang/Checker/BugReporter/BugReporter.h"
17 #include "clang/Checker/PathSensitive/GRStateTrait.h"
18 #include "GRExprEngineExperimentalChecks.h"
19 #include "llvm/ADT/ImmutableSet.h"
21 using namespace clang;
24 class PthreadLockChecker
25 : public CheckerVisitor<PthreadLockChecker> {
28 PthreadLockChecker() : BT(0) {}
29 static void *getTag() {
33 void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
35 void AcquireLock(CheckerContext &C, const CallExpr *CE,
36 SVal lock, bool isTryLock);
38 void ReleaseLock(CheckerContext &C, const CallExpr *CE,
42 } // end anonymous namespace
44 // GDM Entry for tracking lock state.
45 namespace { class LockSet {}; }
47 template <> struct GRStateTrait<LockSet> :
48 public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
49 static void* GDMIndex() { return PthreadLockChecker::getTag(); }
51 } // end clang namespace
53 void clang::RegisterPthreadLockChecker(GRExprEngine &Eng) {
54 Eng.registerCheck(new PthreadLockChecker());
58 void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
60 const GRState *state = C.getState();
61 const Expr *Callee = CE->getCallee();
62 const FunctionTextRegion *R =
63 dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
68 llvm::StringRef FName = R->getDecl()->getName();
70 if (FName == "pthread_mutex_lock") {
71 if (CE->getNumArgs() != 1)
73 AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
75 else if (FName == "pthread_mutex_trylock") {
76 if (CE->getNumArgs() != 1)
78 AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
80 else if (FName == "pthread_mutex_unlock") {
81 if (CE->getNumArgs() != 1)
83 ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
87 void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
88 SVal lock, bool isTryLock) {
90 const MemRegion *lockR = lock.getAsRegion();
94 const GRState *state = C.getState();
96 SVal X = state->getSVal(CE);
97 if (X.isUnknownOrUndef())
100 DefinedSVal retVal = cast<DefinedSVal>(X);
101 const GRState *lockSucc = state;
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));
111 // Assume that the return value was 0.
112 lockSucc = state->Assume(retVal, false);
116 // Record that the lock was acquired.
117 lockSucc = lockSucc->add<LockSet>(lockR);
119 C.addTransition(lockSucc != state ? C.GenerateNode(CE, lockSucc) :
123 void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
126 const MemRegion *lockR = lock.getAsRegion();
130 const GRState *state = C.getState();
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);
137 if (state == unlockState)
140 C.addTransition(C.GenerateNode(CE, unlockState));