xref: /minix3/external/bsd/llvm/dist/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc //===--- PthreadLockChecker.cpp - Check for locking problems ---*- C++ -*--===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // This defines PthreadLockChecker, a simple lock -> unlock checker.
11f4a2713aSLionel Sambuc // Also handles XNU locks, which behave similarly enough to share code.
12f4a2713aSLionel Sambuc //
13f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
14f4a2713aSLionel Sambuc 
15f4a2713aSLionel Sambuc #include "ClangSACheckers.h"
16f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/Checker.h"
18f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/CheckerManager.h"
19f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
21f4a2713aSLionel Sambuc #include "llvm/ADT/ImmutableList.h"
22f4a2713aSLionel Sambuc 
23f4a2713aSLionel Sambuc using namespace clang;
24f4a2713aSLionel Sambuc using namespace ento;
25f4a2713aSLionel Sambuc 
26f4a2713aSLionel Sambuc namespace {
27*0a6a1f1dSLionel Sambuc 
28*0a6a1f1dSLionel Sambuc struct LockState {
29*0a6a1f1dSLionel Sambuc   enum Kind { Destroyed, Locked, Unlocked } K;
30*0a6a1f1dSLionel Sambuc 
31*0a6a1f1dSLionel Sambuc private:
LockState__anon12f036e70111::LockState32*0a6a1f1dSLionel Sambuc   LockState(Kind K) : K(K) {}
33*0a6a1f1dSLionel Sambuc 
34*0a6a1f1dSLionel Sambuc public:
getLocked__anon12f036e70111::LockState35*0a6a1f1dSLionel Sambuc   static LockState getLocked(void) { return LockState(Locked); }
getUnlocked__anon12f036e70111::LockState36*0a6a1f1dSLionel Sambuc   static LockState getUnlocked(void) { return LockState(Unlocked); }
getDestroyed__anon12f036e70111::LockState37*0a6a1f1dSLionel Sambuc   static LockState getDestroyed(void) { return LockState(Destroyed); }
38*0a6a1f1dSLionel Sambuc 
operator ==__anon12f036e70111::LockState39*0a6a1f1dSLionel Sambuc   bool operator==(const LockState &X) const {
40*0a6a1f1dSLionel Sambuc     return K == X.K;
41*0a6a1f1dSLionel Sambuc   }
42*0a6a1f1dSLionel Sambuc 
isLocked__anon12f036e70111::LockState43*0a6a1f1dSLionel Sambuc   bool isLocked() const { return K == Locked; }
isUnlocked__anon12f036e70111::LockState44*0a6a1f1dSLionel Sambuc   bool isUnlocked() const { return K == Unlocked; }
isDestroyed__anon12f036e70111::LockState45*0a6a1f1dSLionel Sambuc   bool isDestroyed() const { return K == Destroyed; }
46*0a6a1f1dSLionel Sambuc 
Profile__anon12f036e70111::LockState47*0a6a1f1dSLionel Sambuc   void Profile(llvm::FoldingSetNodeID &ID) const {
48*0a6a1f1dSLionel Sambuc     ID.AddInteger(K);
49*0a6a1f1dSLionel Sambuc   }
50*0a6a1f1dSLionel Sambuc };
51*0a6a1f1dSLionel Sambuc 
52f4a2713aSLionel Sambuc class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
53*0a6a1f1dSLionel Sambuc   mutable std::unique_ptr<BugType> BT_doublelock;
54*0a6a1f1dSLionel Sambuc   mutable std::unique_ptr<BugType> BT_doubleunlock;
55*0a6a1f1dSLionel Sambuc   mutable std::unique_ptr<BugType> BT_destroylock;
56*0a6a1f1dSLionel Sambuc   mutable std::unique_ptr<BugType> BT_initlock;
57*0a6a1f1dSLionel Sambuc   mutable std::unique_ptr<BugType> BT_lor;
58f4a2713aSLionel Sambuc   enum LockingSemantics {
59f4a2713aSLionel Sambuc     NotApplicable = 0,
60f4a2713aSLionel Sambuc     PthreadSemantics,
61f4a2713aSLionel Sambuc     XNUSemantics
62f4a2713aSLionel Sambuc   };
63f4a2713aSLionel Sambuc public:
64f4a2713aSLionel Sambuc   void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
65f4a2713aSLionel Sambuc 
66f4a2713aSLionel Sambuc   void AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock,
67f4a2713aSLionel Sambuc                    bool isTryLock, enum LockingSemantics semantics) const;
68f4a2713aSLionel Sambuc 
69f4a2713aSLionel Sambuc   void ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) const;
70*0a6a1f1dSLionel Sambuc   void DestroyLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const;
71*0a6a1f1dSLionel Sambuc   void InitLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const;
72*0a6a1f1dSLionel Sambuc   void reportUseDestroyedBug(CheckerContext &C, const CallExpr *CE) const;
73f4a2713aSLionel Sambuc };
74f4a2713aSLionel Sambuc } // end anonymous namespace
75f4a2713aSLionel Sambuc 
76f4a2713aSLionel Sambuc // GDM Entry for tracking lock state.
REGISTER_LIST_WITH_PROGRAMSTATE(LockSet,const MemRegion *)77f4a2713aSLionel Sambuc REGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *)
78f4a2713aSLionel Sambuc 
79*0a6a1f1dSLionel Sambuc REGISTER_MAP_WITH_PROGRAMSTATE(LockMap, const MemRegion *, LockState)
80f4a2713aSLionel Sambuc 
81f4a2713aSLionel Sambuc void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
82f4a2713aSLionel Sambuc                                        CheckerContext &C) const {
83f4a2713aSLionel Sambuc   ProgramStateRef state = C.getState();
84f4a2713aSLionel Sambuc   const LocationContext *LCtx = C.getLocationContext();
85f4a2713aSLionel Sambuc   StringRef FName = C.getCalleeName(CE);
86f4a2713aSLionel Sambuc   if (FName.empty())
87f4a2713aSLionel Sambuc     return;
88f4a2713aSLionel Sambuc 
89*0a6a1f1dSLionel Sambuc   if (CE->getNumArgs() != 1 && CE->getNumArgs() != 2)
90f4a2713aSLionel Sambuc     return;
91f4a2713aSLionel Sambuc 
92f4a2713aSLionel Sambuc   if (FName == "pthread_mutex_lock" ||
93f4a2713aSLionel Sambuc       FName == "pthread_rwlock_rdlock" ||
94f4a2713aSLionel Sambuc       FName == "pthread_rwlock_wrlock")
95f4a2713aSLionel Sambuc     AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
96f4a2713aSLionel Sambuc                 false, PthreadSemantics);
97f4a2713aSLionel Sambuc   else if (FName == "lck_mtx_lock" ||
98f4a2713aSLionel Sambuc            FName == "lck_rw_lock_exclusive" ||
99f4a2713aSLionel Sambuc            FName == "lck_rw_lock_shared")
100f4a2713aSLionel Sambuc     AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
101f4a2713aSLionel Sambuc                 false, XNUSemantics);
102f4a2713aSLionel Sambuc   else if (FName == "pthread_mutex_trylock" ||
103f4a2713aSLionel Sambuc            FName == "pthread_rwlock_tryrdlock" ||
104*0a6a1f1dSLionel Sambuc            FName == "pthread_rwlock_trywrlock")
105f4a2713aSLionel Sambuc     AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
106f4a2713aSLionel Sambuc                 true, PthreadSemantics);
107f4a2713aSLionel Sambuc   else if (FName == "lck_mtx_try_lock" ||
108f4a2713aSLionel Sambuc            FName == "lck_rw_try_lock_exclusive" ||
109f4a2713aSLionel Sambuc            FName == "lck_rw_try_lock_shared")
110f4a2713aSLionel Sambuc     AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
111f4a2713aSLionel Sambuc                 true, XNUSemantics);
112f4a2713aSLionel Sambuc   else if (FName == "pthread_mutex_unlock" ||
113f4a2713aSLionel Sambuc            FName == "pthread_rwlock_unlock" ||
114f4a2713aSLionel Sambuc            FName == "lck_mtx_unlock" ||
115f4a2713aSLionel Sambuc            FName == "lck_rw_done")
116f4a2713aSLionel Sambuc     ReleaseLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
117*0a6a1f1dSLionel Sambuc   else if (FName == "pthread_mutex_destroy" ||
118*0a6a1f1dSLionel Sambuc            FName == "lck_mtx_destroy")
119*0a6a1f1dSLionel Sambuc     DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
120*0a6a1f1dSLionel Sambuc   else if (FName == "pthread_mutex_init")
121*0a6a1f1dSLionel Sambuc     InitLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
122f4a2713aSLionel Sambuc }
123f4a2713aSLionel Sambuc 
AcquireLock(CheckerContext & C,const CallExpr * CE,SVal lock,bool isTryLock,enum LockingSemantics semantics) const124f4a2713aSLionel Sambuc void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
125f4a2713aSLionel Sambuc                                      SVal lock, bool isTryLock,
126f4a2713aSLionel Sambuc                                      enum LockingSemantics semantics) const {
127f4a2713aSLionel Sambuc 
128f4a2713aSLionel Sambuc   const MemRegion *lockR = lock.getAsRegion();
129f4a2713aSLionel Sambuc   if (!lockR)
130f4a2713aSLionel Sambuc     return;
131f4a2713aSLionel Sambuc 
132f4a2713aSLionel Sambuc   ProgramStateRef state = C.getState();
133f4a2713aSLionel Sambuc 
134f4a2713aSLionel Sambuc   SVal X = state->getSVal(CE, C.getLocationContext());
135f4a2713aSLionel Sambuc   if (X.isUnknownOrUndef())
136f4a2713aSLionel Sambuc     return;
137f4a2713aSLionel Sambuc 
138f4a2713aSLionel Sambuc   DefinedSVal retVal = X.castAs<DefinedSVal>();
139f4a2713aSLionel Sambuc 
140*0a6a1f1dSLionel Sambuc   if (const LockState *LState = state->get<LockMap>(lockR)) {
141*0a6a1f1dSLionel Sambuc     if (LState->isLocked()) {
142f4a2713aSLionel Sambuc       if (!BT_doublelock)
143*0a6a1f1dSLionel Sambuc         BT_doublelock.reset(new BugType(this, "Double locking",
144*0a6a1f1dSLionel Sambuc                                         "Lock checker"));
145f4a2713aSLionel Sambuc       ExplodedNode *N = C.generateSink();
146f4a2713aSLionel Sambuc       if (!N)
147f4a2713aSLionel Sambuc         return;
148f4a2713aSLionel Sambuc       BugReport *report = new BugReport(*BT_doublelock,
149*0a6a1f1dSLionel Sambuc                                         "This lock has already been acquired",
150*0a6a1f1dSLionel Sambuc                                         N);
151f4a2713aSLionel Sambuc       report->addRange(CE->getArg(0)->getSourceRange());
152f4a2713aSLionel Sambuc       C.emitReport(report);
153f4a2713aSLionel Sambuc       return;
154*0a6a1f1dSLionel Sambuc     } else if (LState->isDestroyed()) {
155*0a6a1f1dSLionel Sambuc       reportUseDestroyedBug(C, CE);
156*0a6a1f1dSLionel Sambuc       return;
157*0a6a1f1dSLionel Sambuc     }
158f4a2713aSLionel Sambuc   }
159f4a2713aSLionel Sambuc 
160f4a2713aSLionel Sambuc   ProgramStateRef lockSucc = state;
161f4a2713aSLionel Sambuc   if (isTryLock) {
162f4a2713aSLionel Sambuc     // Bifurcate the state, and allow a mode where the lock acquisition fails.
163f4a2713aSLionel Sambuc     ProgramStateRef lockFail;
164f4a2713aSLionel Sambuc     switch (semantics) {
165f4a2713aSLionel Sambuc     case PthreadSemantics:
166*0a6a1f1dSLionel Sambuc       std::tie(lockFail, lockSucc) = state->assume(retVal);
167f4a2713aSLionel Sambuc       break;
168f4a2713aSLionel Sambuc     case XNUSemantics:
169*0a6a1f1dSLionel Sambuc       std::tie(lockSucc, lockFail) = state->assume(retVal);
170f4a2713aSLionel Sambuc       break;
171f4a2713aSLionel Sambuc     default:
172f4a2713aSLionel Sambuc       llvm_unreachable("Unknown tryLock locking semantics");
173f4a2713aSLionel Sambuc     }
174f4a2713aSLionel Sambuc     assert(lockFail && lockSucc);
175f4a2713aSLionel Sambuc     C.addTransition(lockFail);
176f4a2713aSLionel Sambuc 
177f4a2713aSLionel Sambuc   } else if (semantics == PthreadSemantics) {
178f4a2713aSLionel Sambuc     // Assume that the return value was 0.
179f4a2713aSLionel Sambuc     lockSucc = state->assume(retVal, false);
180f4a2713aSLionel Sambuc     assert(lockSucc);
181f4a2713aSLionel Sambuc 
182f4a2713aSLionel Sambuc   } else {
183f4a2713aSLionel Sambuc     // XNU locking semantics return void on non-try locks
184f4a2713aSLionel Sambuc     assert((semantics == XNUSemantics) && "Unknown locking semantics");
185f4a2713aSLionel Sambuc     lockSucc = state;
186f4a2713aSLionel Sambuc   }
187f4a2713aSLionel Sambuc 
188f4a2713aSLionel Sambuc   // Record that the lock was acquired.
189f4a2713aSLionel Sambuc   lockSucc = lockSucc->add<LockSet>(lockR);
190*0a6a1f1dSLionel Sambuc   lockSucc = lockSucc->set<LockMap>(lockR, LockState::getLocked());
191f4a2713aSLionel Sambuc   C.addTransition(lockSucc);
192f4a2713aSLionel Sambuc }
193f4a2713aSLionel Sambuc 
ReleaseLock(CheckerContext & C,const CallExpr * CE,SVal lock) const194f4a2713aSLionel Sambuc void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
195f4a2713aSLionel Sambuc                                      SVal lock) const {
196f4a2713aSLionel Sambuc 
197f4a2713aSLionel Sambuc   const MemRegion *lockR = lock.getAsRegion();
198f4a2713aSLionel Sambuc   if (!lockR)
199f4a2713aSLionel Sambuc     return;
200f4a2713aSLionel Sambuc 
201f4a2713aSLionel Sambuc   ProgramStateRef state = C.getState();
202*0a6a1f1dSLionel Sambuc 
203*0a6a1f1dSLionel Sambuc   if (const LockState *LState = state->get<LockMap>(lockR)) {
204*0a6a1f1dSLionel Sambuc     if (LState->isUnlocked()) {
205*0a6a1f1dSLionel Sambuc       if (!BT_doubleunlock)
206*0a6a1f1dSLionel Sambuc         BT_doubleunlock.reset(new BugType(this, "Double unlocking",
207*0a6a1f1dSLionel Sambuc                                           "Lock checker"));
208*0a6a1f1dSLionel Sambuc       ExplodedNode *N = C.generateSink();
209*0a6a1f1dSLionel Sambuc       if (!N)
210*0a6a1f1dSLionel Sambuc         return;
211*0a6a1f1dSLionel Sambuc       BugReport *Report = new BugReport(*BT_doubleunlock,
212*0a6a1f1dSLionel Sambuc                                         "This lock has already been unlocked",
213*0a6a1f1dSLionel Sambuc                                         N);
214*0a6a1f1dSLionel Sambuc       Report->addRange(CE->getArg(0)->getSourceRange());
215*0a6a1f1dSLionel Sambuc       C.emitReport(Report);
216*0a6a1f1dSLionel Sambuc       return;
217*0a6a1f1dSLionel Sambuc     } else if (LState->isDestroyed()) {
218*0a6a1f1dSLionel Sambuc       reportUseDestroyedBug(C, CE);
219*0a6a1f1dSLionel Sambuc       return;
220*0a6a1f1dSLionel Sambuc     }
221*0a6a1f1dSLionel Sambuc   }
222*0a6a1f1dSLionel Sambuc 
223f4a2713aSLionel Sambuc   LockSetTy LS = state->get<LockSet>();
224f4a2713aSLionel Sambuc 
225f4a2713aSLionel Sambuc   // FIXME: Better analysis requires IPA for wrappers.
226f4a2713aSLionel Sambuc 
227*0a6a1f1dSLionel Sambuc   if (!LS.isEmpty()) {
228f4a2713aSLionel Sambuc     const MemRegion *firstLockR = LS.getHead();
229f4a2713aSLionel Sambuc     if (firstLockR != lockR) {
230f4a2713aSLionel Sambuc       if (!BT_lor)
231*0a6a1f1dSLionel Sambuc         BT_lor.reset(new BugType(this, "Lock order reversal", "Lock checker"));
232f4a2713aSLionel Sambuc       ExplodedNode *N = C.generateSink();
233f4a2713aSLionel Sambuc       if (!N)
234f4a2713aSLionel Sambuc         return;
235f4a2713aSLionel Sambuc       BugReport *report = new BugReport(*BT_lor,
236*0a6a1f1dSLionel Sambuc                                         "This was not the most recently "
237*0a6a1f1dSLionel Sambuc                                         "acquired lock. Possible lock order "
238*0a6a1f1dSLionel Sambuc                                         "reversal",
239*0a6a1f1dSLionel Sambuc                                         N);
240f4a2713aSLionel Sambuc       report->addRange(CE->getArg(0)->getSourceRange());
241f4a2713aSLionel Sambuc       C.emitReport(report);
242f4a2713aSLionel Sambuc       return;
243f4a2713aSLionel Sambuc     }
244f4a2713aSLionel Sambuc     // Record that the lock was released.
245f4a2713aSLionel Sambuc     state = state->set<LockSet>(LS.getTail());
246*0a6a1f1dSLionel Sambuc   }
247*0a6a1f1dSLionel Sambuc 
248*0a6a1f1dSLionel Sambuc   state = state->set<LockMap>(lockR, LockState::getUnlocked());
249f4a2713aSLionel Sambuc   C.addTransition(state);
250f4a2713aSLionel Sambuc }
251f4a2713aSLionel Sambuc 
DestroyLock(CheckerContext & C,const CallExpr * CE,SVal Lock) const252*0a6a1f1dSLionel Sambuc void PthreadLockChecker::DestroyLock(CheckerContext &C, const CallExpr *CE,
253*0a6a1f1dSLionel Sambuc                                      SVal Lock) const {
254*0a6a1f1dSLionel Sambuc 
255*0a6a1f1dSLionel Sambuc   const MemRegion *LockR = Lock.getAsRegion();
256*0a6a1f1dSLionel Sambuc   if (!LockR)
257*0a6a1f1dSLionel Sambuc     return;
258*0a6a1f1dSLionel Sambuc 
259*0a6a1f1dSLionel Sambuc   ProgramStateRef State = C.getState();
260*0a6a1f1dSLionel Sambuc 
261*0a6a1f1dSLionel Sambuc   const LockState *LState = State->get<LockMap>(LockR);
262*0a6a1f1dSLionel Sambuc   if (!LState || LState->isUnlocked()) {
263*0a6a1f1dSLionel Sambuc     State = State->set<LockMap>(LockR, LockState::getDestroyed());
264*0a6a1f1dSLionel Sambuc     C.addTransition(State);
265*0a6a1f1dSLionel Sambuc     return;
266*0a6a1f1dSLionel Sambuc   }
267*0a6a1f1dSLionel Sambuc 
268*0a6a1f1dSLionel Sambuc   StringRef Message;
269*0a6a1f1dSLionel Sambuc 
270*0a6a1f1dSLionel Sambuc   if (LState->isLocked()) {
271*0a6a1f1dSLionel Sambuc     Message = "This lock is still locked";
272*0a6a1f1dSLionel Sambuc   } else {
273*0a6a1f1dSLionel Sambuc     Message = "This lock has already been destroyed";
274*0a6a1f1dSLionel Sambuc   }
275*0a6a1f1dSLionel Sambuc 
276*0a6a1f1dSLionel Sambuc   if (!BT_destroylock)
277*0a6a1f1dSLionel Sambuc     BT_destroylock.reset(new BugType(this, "Destroy invalid lock",
278*0a6a1f1dSLionel Sambuc                                      "Lock checker"));
279*0a6a1f1dSLionel Sambuc   ExplodedNode *N = C.generateSink();
280*0a6a1f1dSLionel Sambuc   if (!N)
281*0a6a1f1dSLionel Sambuc     return;
282*0a6a1f1dSLionel Sambuc   BugReport *Report = new BugReport(*BT_destroylock, Message, N);
283*0a6a1f1dSLionel Sambuc   Report->addRange(CE->getArg(0)->getSourceRange());
284*0a6a1f1dSLionel Sambuc   C.emitReport(Report);
285*0a6a1f1dSLionel Sambuc }
286*0a6a1f1dSLionel Sambuc 
InitLock(CheckerContext & C,const CallExpr * CE,SVal Lock) const287*0a6a1f1dSLionel Sambuc void PthreadLockChecker::InitLock(CheckerContext &C, const CallExpr *CE,
288*0a6a1f1dSLionel Sambuc                                   SVal Lock) const {
289*0a6a1f1dSLionel Sambuc 
290*0a6a1f1dSLionel Sambuc   const MemRegion *LockR = Lock.getAsRegion();
291*0a6a1f1dSLionel Sambuc   if (!LockR)
292*0a6a1f1dSLionel Sambuc     return;
293*0a6a1f1dSLionel Sambuc 
294*0a6a1f1dSLionel Sambuc   ProgramStateRef State = C.getState();
295*0a6a1f1dSLionel Sambuc 
296*0a6a1f1dSLionel Sambuc   const struct LockState *LState = State->get<LockMap>(LockR);
297*0a6a1f1dSLionel Sambuc   if (!LState || LState->isDestroyed()) {
298*0a6a1f1dSLionel Sambuc     State = State->set<LockMap>(LockR, LockState::getUnlocked());
299*0a6a1f1dSLionel Sambuc     C.addTransition(State);
300*0a6a1f1dSLionel Sambuc     return;
301*0a6a1f1dSLionel Sambuc   }
302*0a6a1f1dSLionel Sambuc 
303*0a6a1f1dSLionel Sambuc   StringRef Message;
304*0a6a1f1dSLionel Sambuc 
305*0a6a1f1dSLionel Sambuc   if (LState->isLocked()) {
306*0a6a1f1dSLionel Sambuc     Message = "This lock is still being held";
307*0a6a1f1dSLionel Sambuc   } else {
308*0a6a1f1dSLionel Sambuc     Message = "This lock has already been initialized";
309*0a6a1f1dSLionel Sambuc   }
310*0a6a1f1dSLionel Sambuc 
311*0a6a1f1dSLionel Sambuc   if (!BT_initlock)
312*0a6a1f1dSLionel Sambuc     BT_initlock.reset(new BugType(this, "Init invalid lock",
313*0a6a1f1dSLionel Sambuc                                   "Lock checker"));
314*0a6a1f1dSLionel Sambuc   ExplodedNode *N = C.generateSink();
315*0a6a1f1dSLionel Sambuc   if (!N)
316*0a6a1f1dSLionel Sambuc     return;
317*0a6a1f1dSLionel Sambuc   BugReport *Report = new BugReport(*BT_initlock, Message, N);
318*0a6a1f1dSLionel Sambuc   Report->addRange(CE->getArg(0)->getSourceRange());
319*0a6a1f1dSLionel Sambuc   C.emitReport(Report);
320*0a6a1f1dSLionel Sambuc }
321*0a6a1f1dSLionel Sambuc 
reportUseDestroyedBug(CheckerContext & C,const CallExpr * CE) const322*0a6a1f1dSLionel Sambuc void PthreadLockChecker::reportUseDestroyedBug(CheckerContext &C,
323*0a6a1f1dSLionel Sambuc                                                const CallExpr *CE) const {
324*0a6a1f1dSLionel Sambuc   if (!BT_destroylock)
325*0a6a1f1dSLionel Sambuc     BT_destroylock.reset(new BugType(this, "Use destroyed lock",
326*0a6a1f1dSLionel Sambuc                                      "Lock checker"));
327*0a6a1f1dSLionel Sambuc   ExplodedNode *N = C.generateSink();
328*0a6a1f1dSLionel Sambuc   if (!N)
329*0a6a1f1dSLionel Sambuc     return;
330*0a6a1f1dSLionel Sambuc   BugReport *Report = new BugReport(*BT_destroylock,
331*0a6a1f1dSLionel Sambuc                                     "This lock has already been destroyed",
332*0a6a1f1dSLionel Sambuc                                     N);
333*0a6a1f1dSLionel Sambuc   Report->addRange(CE->getArg(0)->getSourceRange());
334*0a6a1f1dSLionel Sambuc   C.emitReport(Report);
335*0a6a1f1dSLionel Sambuc }
336f4a2713aSLionel Sambuc 
registerPthreadLockChecker(CheckerManager & mgr)337f4a2713aSLionel Sambuc void ento::registerPthreadLockChecker(CheckerManager &mgr) {
338f4a2713aSLionel Sambuc   mgr.registerChecker<PthreadLockChecker>();
339f4a2713aSLionel Sambuc }
340