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