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