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 ExprEngineInternalChecks.
13 //===----------------------------------------------------------------------===//
15 #include "ClangSACheckers.h"
16 #include "clang/StaticAnalyzer/Core/Checker.h"
17 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
18 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
19 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
21 #include "llvm/ADT/ImmutableSet.h"
23 using namespace clang;
27 class PthreadLockChecker
28 : public Checker< check::PostStmt<CallExpr> > {
30 void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
32 void AcquireLock(CheckerContext &C, const CallExpr *CE,
33 SVal lock, bool isTryLock) const;
35 void ReleaseLock(CheckerContext &C, const CallExpr *CE,
39 } // end anonymous namespace
41 // GDM Entry for tracking lock state.
42 namespace { class LockSet {}; }
45 template <> struct GRStateTrait<LockSet> :
46 public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
47 static void* GDMIndex() { static int x = 0; return &x; }
50 } // end clang namespace
53 void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
54 CheckerContext &C) const {
55 const GRState *state = C.getState();
56 const Expr *Callee = CE->getCallee();
57 const FunctionTextRegion *R =
58 dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
63 IdentifierInfo *II = R->getDecl()->getIdentifier();
64 if (!II) // if no identifier, not a simple C function
66 llvm::StringRef FName = II->getName();
68 if (FName == "pthread_mutex_lock") {
69 if (CE->getNumArgs() != 1)
71 AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
73 else if (FName == "pthread_mutex_trylock") {
74 if (CE->getNumArgs() != 1)
76 AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
78 else if (FName == "pthread_mutex_unlock") {
79 if (CE->getNumArgs() != 1)
81 ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
85 void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
86 SVal lock, bool isTryLock) const {
88 const MemRegion *lockR = lock.getAsRegion();
92 const GRState *state = C.getState();
94 SVal X = state->getSVal(CE);
95 if (X.isUnknownOrUndef())
98 DefinedSVal retVal = cast<DefinedSVal>(X);
99 const GRState *lockSucc = state;
102 // Bifurcate the state, and allow a mode where the lock acquisition fails.
103 const GRState *lockFail;
104 llvm::tie(lockFail, lockSucc) = state->assume(retVal);
105 assert(lockFail && lockSucc);
106 C.addTransition(C.generateNode(CE, lockFail));
109 // Assume that the return value was 0.
110 lockSucc = state->assume(retVal, false);
114 // Record that the lock was acquired.
115 lockSucc = lockSucc->add<LockSet>(lockR);
117 C.addTransition(lockSucc != state ? C.generateNode(CE, lockSucc) :
121 void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
124 const MemRegion *lockR = lock.getAsRegion();
128 const GRState *state = C.getState();
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);
135 if (state == unlockState)
138 C.addTransition(C.generateNode(CE, unlockState));
141 void ento::registerPthreadLockChecker(CheckerManager &mgr) {
142 mgr.registerChecker<PthreadLockChecker>();