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