1dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose//===--- PthreadLockChecker.cpp - Check for locking problems ---*- C++ -*--===// 2ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek// 3ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek// The LLVM Compiler Infrastructure 4ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek// 5ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek// This file is distributed under the University of Illinois Open Source 6ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek// License. See LICENSE.TXT for details. 7ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek// 8ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek//===----------------------------------------------------------------------===// 9ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek// 104cc1187e8a04f1f36e8c3656f65097e770bdc437Jordy Rose// This defines PthreadLockChecker, a simple lock -> unlock checker. 114cc1187e8a04f1f36e8c3656f65097e770bdc437Jordy Rose// Also handles XNU locks, which behave similarly enough to share code. 12ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek// 13ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek//===----------------------------------------------------------------------===// 14ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 15a0decc9a2481f938e1675b4f7bbd58761a882a36Argyrios Kyrtzidis#include "ClangSACheckers.h" 1655fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 17ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h" 18695fb502825a53ccd178ec1c85c77929d88acb71Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/CheckerManager.h" 19983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 2018c66fdc3c4008d335885695fe36fb5353c5f672Ted Kremenek#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 21dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose#include "llvm/ADT/ImmutableList.h" 22ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 23ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenekusing namespace clang; 249ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento; 25ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 26ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremeneknamespace { 27651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 28651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesstruct LockState { 29651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines enum Kind { Destroyed, Locked, Unlocked } K; 30651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 31651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesprivate: 32651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines LockState(Kind K) : K(K) {} 33651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 34651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic: 35651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines static LockState getLocked(void) { return LockState(Locked); } 36651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines static LockState getUnlocked(void) { return LockState(Unlocked); } 37651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines static LockState getDestroyed(void) { return LockState(Destroyed); } 38651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 39651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines bool operator==(const LockState &X) const { 40651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines return K == X.K; 41651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } 42651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 43651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines bool isLocked() const { return K == Locked; } 44651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines bool isUnlocked() const { return K == Unlocked; } 45651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines bool isDestroyed() const { return K == Destroyed; } 46651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 47651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines void Profile(llvm::FoldingSetNodeID &ID) const { 48651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines ID.AddInteger(K); 49651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } 50651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}; 51651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 52dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Roseclass PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > { 53651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines mutable std::unique_ptr<BugType> BT_doublelock; 54651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines mutable std::unique_ptr<BugType> BT_doubleunlock; 55651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines mutable std::unique_ptr<BugType> BT_destroylock; 56651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines mutable std::unique_ptr<BugType> BT_initlock; 57651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines mutable std::unique_ptr<BugType> BT_lor; 58dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose enum LockingSemantics { 59dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose NotApplicable = 0, 60dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose PthreadSemantics, 61dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose XNUSemantics 62dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose }; 63ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenekpublic: 64983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; 65ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 66dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose void AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock, 67dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose bool isTryLock, enum LockingSemantics semantics) const; 68ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 69dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose void ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) const; 70651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines void DestroyLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const; 71651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines void InitLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const; 72651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines void reportUseDestroyedBug(CheckerContext &C, const CallExpr *CE) const; 73ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek}; 74ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek} // end anonymous namespace 75ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 76ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek// GDM Entry for tracking lock state. 77166d502d5367ceacd1313a33cac43b1048b8524dJordan RoseREGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *) 78ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 79651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesREGISTER_MAP_WITH_PROGRAMSTATE(LockMap, const MemRegion *, LockState) 80695fb502825a53ccd178ec1c85c77929d88acb71Argyrios Kyrtzidis 81983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidisvoid PthreadLockChecker::checkPostStmt(const CallExpr *CE, 82983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis CheckerContext &C) const { 838bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek ProgramStateRef state = C.getState(); 845eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek const LocationContext *LCtx = C.getLocationContext(); 85b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks StringRef FName = C.getCalleeName(CE); 86b805c8ff133ef0c62df032fa711d6b13c5afd7f4Anna Zaks if (FName.empty()) 8790d26a4afdbf6d917a5241ef3b316e1c8337c9b8Douglas Gregor return; 88dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose 89651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (CE->getNumArgs() != 1 && CE->getNumArgs() != 2) 90dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose return; 914cc1187e8a04f1f36e8c3656f65097e770bdc437Jordy Rose 92dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose if (FName == "pthread_mutex_lock" || 93dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose FName == "pthread_rwlock_rdlock" || 94dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose FName == "pthread_rwlock_wrlock") 955eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx), 965eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek false, PthreadSemantics); 97dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose else if (FName == "lck_mtx_lock" || 98dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose FName == "lck_rw_lock_exclusive" || 99dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose FName == "lck_rw_lock_shared") 1005eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx), 1015eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek false, XNUSemantics); 102dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose else if (FName == "pthread_mutex_trylock" || 103dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose FName == "pthread_rwlock_tryrdlock" || 104651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines FName == "pthread_rwlock_trywrlock") 1055eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx), 1065eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek true, PthreadSemantics); 107dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose else if (FName == "lck_mtx_try_lock" || 108dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose FName == "lck_rw_try_lock_exclusive" || 109dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose FName == "lck_rw_try_lock_shared") 1105eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx), 1115eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek true, XNUSemantics); 112dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose else if (FName == "pthread_mutex_unlock" || 113dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose FName == "pthread_rwlock_unlock" || 114dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose FName == "lck_mtx_unlock" || 115dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose FName == "lck_rw_done") 1165eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek ReleaseLock(C, CE, state->getSVal(CE->getArg(0), LCtx)); 117651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines else if (FName == "pthread_mutex_destroy" || 118651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines FName == "lck_mtx_destroy") 119651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx)); 120651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines else if (FName == "pthread_mutex_init") 121651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines InitLock(C, CE, state->getSVal(CE->getArg(0), LCtx)); 122ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek} 123ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 124ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenekvoid PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE, 125dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose SVal lock, bool isTryLock, 126dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose enum LockingSemantics semantics) const { 127ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 128ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek const MemRegion *lockR = lock.getAsRegion(); 129ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek if (!lockR) 130ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek return; 131ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 1328bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek ProgramStateRef state = C.getState(); 133ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 1345eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek SVal X = state->getSVal(CE, C.getLocationContext()); 135ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek if (X.isUnknownOrUndef()) 136ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek return; 137ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 1385251abea41b446c26e3239c8dd6c7edea6fc335dDavid Blaikie DefinedSVal retVal = X.castAs<DefinedSVal>(); 139dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose 140651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (const LockState *LState = state->get<LockMap>(lockR)) { 141651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (LState->isLocked()) { 142651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!BT_doublelock) 143651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BT_doublelock.reset(new BugType(this, "Double locking", 144651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines "Lock checker")); 145651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines ExplodedNode *N = C.generateSink(); 146651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!N) 147651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines return; 148651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BugReport *report = new BugReport(*BT_doublelock, 149651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines "This lock has already been acquired", 150651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines N); 151651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines report->addRange(CE->getArg(0)->getSourceRange()); 152651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines C.emitReport(report); 153dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose return; 154651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } else if (LState->isDestroyed()) { 155651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines reportUseDestroyedBug(C, CE); 156651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines return; 157651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } 158dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose } 159dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose 1608bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek ProgramStateRef lockSucc = state; 161ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek if (isTryLock) { 162dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose // Bifurcate the state, and allow a mode where the lock acquisition fails. 1638bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek ProgramStateRef lockFail; 164dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose switch (semantics) { 165dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose case PthreadSemantics: 166651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines std::tie(lockFail, lockSucc) = state->assume(retVal); 167dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose break; 168dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose case XNUSemantics: 169651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines std::tie(lockSucc, lockFail) = state->assume(retVal); 170dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose break; 171dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose default: 172dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose llvm_unreachable("Unknown tryLock locking semantics"); 173dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose } 174ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek assert(lockFail && lockSucc); 1750bd6b110e908892d4b5c8671a9f435a1d72ad16aAnna Zaks C.addTransition(lockFail); 176dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose 177dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose } else if (semantics == PthreadSemantics) { 178dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose // Assume that the return value was 0. 17928f47b92e760ccf641ac91cb0fe1c12d9ca89795Ted Kremenek lockSucc = state->assume(retVal, false); 180ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek assert(lockSucc); 181dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose 182dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose } else { 183dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose // XNU locking semantics return void on non-try locks 184dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose assert((semantics == XNUSemantics) && "Unknown locking semantics"); 185dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose lockSucc = state; 186ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek } 187ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 188dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose // Record that the lock was acquired. 189ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek lockSucc = lockSucc->add<LockSet>(lockR); 190651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines lockSucc = lockSucc->set<LockMap>(lockR, LockState::getLocked()); 1910bd6b110e908892d4b5c8671a9f435a1d72ad16aAnna Zaks C.addTransition(lockSucc); 192ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek} 193ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 194ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenekvoid PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE, 195983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis SVal lock) const { 196ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 197ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek const MemRegion *lockR = lock.getAsRegion(); 198ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek if (!lockR) 199ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek return; 200ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 2018bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek ProgramStateRef state = C.getState(); 202651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 203651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (const LockState *LState = state->get<LockMap>(lockR)) { 204651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (LState->isUnlocked()) { 205651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!BT_doubleunlock) 206651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BT_doubleunlock.reset(new BugType(this, "Double unlocking", 207651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines "Lock checker")); 208651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines ExplodedNode *N = C.generateSink(); 209651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!N) 210651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines return; 211651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BugReport *Report = new BugReport(*BT_doubleunlock, 212651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines "This lock has already been unlocked", 213651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines N); 214651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines Report->addRange(CE->getArg(0)->getSourceRange()); 215651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines C.emitReport(Report); 216651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines return; 217651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } else if (LState->isDestroyed()) { 218651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines reportUseDestroyedBug(C, CE); 219651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines return; 220651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } 221651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } 222651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 223166d502d5367ceacd1313a33cac43b1048b8524dJordan Rose LockSetTy LS = state->get<LockSet>(); 224ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek 225dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose // FIXME: Better analysis requires IPA for wrappers. 226651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 227651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!LS.isEmpty()) { 228651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines const MemRegion *firstLockR = LS.getHead(); 229651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (firstLockR != lockR) { 230651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!BT_lor) 231651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BT_lor.reset(new BugType(this, "Lock order reversal", "Lock checker")); 232651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines ExplodedNode *N = C.generateSink(); 233651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!N) 234651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines return; 235651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BugReport *report = new BugReport(*BT_lor, 236651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines "This was not the most recently " 237651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines "acquired lock. Possible lock order " 238651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines "reversal", 239651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines N); 240651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines report->addRange(CE->getArg(0)->getSourceRange()); 241651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines C.emitReport(report); 242dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose return; 243651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } 244651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines // Record that the lock was released. 245651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines state = state->set<LockSet>(LS.getTail()); 246dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose } 247dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose 248651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines state = state->set<LockMap>(lockR, LockState::getUnlocked()); 2490bd6b110e908892d4b5c8671a9f435a1d72ad16aAnna Zaks C.addTransition(state); 250ac9bea8bb7a4f1821d63aaa926b60062311b2aa3Ted Kremenek} 251983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis 252651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesvoid PthreadLockChecker::DestroyLock(CheckerContext &C, const CallExpr *CE, 253651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines SVal Lock) const { 254651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 255651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines const MemRegion *LockR = Lock.getAsRegion(); 256651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!LockR) 257651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines return; 258651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 259651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines ProgramStateRef State = C.getState(); 260651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 261651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines const LockState *LState = State->get<LockMap>(LockR); 262651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!LState || LState->isUnlocked()) { 263651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines State = State->set<LockMap>(LockR, LockState::getDestroyed()); 264651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines C.addTransition(State); 265651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines return; 266651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } 267651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 268651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines StringRef Message; 269651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 270651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (LState->isLocked()) { 271651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines Message = "This lock is still locked"; 272651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } else { 273651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines Message = "This lock has already been destroyed"; 274651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } 275651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 276651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!BT_destroylock) 277651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BT_destroylock.reset(new BugType(this, "Destroy invalid lock", 278651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines "Lock checker")); 279651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines ExplodedNode *N = C.generateSink(); 280651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!N) 281651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines return; 282651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BugReport *Report = new BugReport(*BT_destroylock, Message, N); 283651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines Report->addRange(CE->getArg(0)->getSourceRange()); 284651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines C.emitReport(Report); 285651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines} 286651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 287651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesvoid PthreadLockChecker::InitLock(CheckerContext &C, const CallExpr *CE, 288651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines SVal Lock) const { 289651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 290651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines const MemRegion *LockR = Lock.getAsRegion(); 291651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!LockR) 292651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines return; 293651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 294651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines ProgramStateRef State = C.getState(); 295651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 296651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines const struct LockState *LState = State->get<LockMap>(LockR); 297651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!LState || LState->isDestroyed()) { 298651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines State = State->set<LockMap>(LockR, LockState::getUnlocked()); 299651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines C.addTransition(State); 300651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines return; 301651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } 302651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 303651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines StringRef Message; 304651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 305651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (LState->isLocked()) { 306651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines Message = "This lock is still being held"; 307651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } else { 308651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines Message = "This lock has already been initialized"; 309651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } 310651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 311651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!BT_initlock) 312651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BT_initlock.reset(new BugType(this, "Init invalid lock", 313651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines "Lock checker")); 314651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines ExplodedNode *N = C.generateSink(); 315651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!N) 316651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines return; 317651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BugReport *Report = new BugReport(*BT_initlock, Message, N); 318651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines Report->addRange(CE->getArg(0)->getSourceRange()); 319651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines C.emitReport(Report); 320651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines} 321651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 322651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesvoid PthreadLockChecker::reportUseDestroyedBug(CheckerContext &C, 323651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines const CallExpr *CE) const { 324651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!BT_destroylock) 325651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BT_destroylock.reset(new BugType(this, "Use destroyed lock", 326651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines "Lock checker")); 327651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines ExplodedNode *N = C.generateSink(); 328651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!N) 329651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines return; 330651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BugReport *Report = new BugReport(*BT_destroylock, 331651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines "This lock has already been destroyed", 332651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines N); 333651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines Report->addRange(CE->getArg(0)->getSourceRange()); 334651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines C.emitReport(Report); 335651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines} 336dcb1d5d681d857eb7f534dec1f2b3d5a9f81d1f1Jordy Rose 337983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidisvoid ento::registerPthreadLockChecker(CheckerManager &mgr) { 338983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis mgr.registerChecker<PthreadLockChecker>(); 339983326f32c746f5e47161a73758e4d363263dd2cArgyrios Kyrtzidis} 340