PthreadLockChecker.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. //===--- PthreadLockChecker.cpp - Check for locking problems ---*- C++ -*--===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file defines:
  10. // * PthreadLockChecker, a simple lock -> unlock checker.
  11. // Which also checks for XNU locks, which behave similarly enough to share
  12. // code.
  13. // * FuchsiaLocksChecker, which is also rather similar.
  14. // * C11LockChecker which also closely follows Pthread semantics.
  15. //
  16. // TODO: Path notes.
  17. //
  18. //===----------------------------------------------------------------------===//
  19. #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
  20. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  21. #include "clang/StaticAnalyzer/Core/Checker.h"
  22. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  23. #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
  24. #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
  25. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  26. using namespace clang;
  27. using namespace ento;
  28. namespace {
  29. struct LockState {
  30. enum Kind {
  31. Destroyed,
  32. Locked,
  33. Unlocked,
  34. UntouchedAndPossiblyDestroyed,
  35. UnlockedAndPossiblyDestroyed
  36. } K;
  37. private:
  38. LockState(Kind K) : K(K) {}
  39. public:
  40. static LockState getLocked() { return LockState(Locked); }
  41. static LockState getUnlocked() { return LockState(Unlocked); }
  42. static LockState getDestroyed() { return LockState(Destroyed); }
  43. static LockState getUntouchedAndPossiblyDestroyed() {
  44. return LockState(UntouchedAndPossiblyDestroyed);
  45. }
  46. static LockState getUnlockedAndPossiblyDestroyed() {
  47. return LockState(UnlockedAndPossiblyDestroyed);
  48. }
  49. bool operator==(const LockState &X) const { return K == X.K; }
  50. bool isLocked() const { return K == Locked; }
  51. bool isUnlocked() const { return K == Unlocked; }
  52. bool isDestroyed() const { return K == Destroyed; }
  53. bool isUntouchedAndPossiblyDestroyed() const {
  54. return K == UntouchedAndPossiblyDestroyed;
  55. }
  56. bool isUnlockedAndPossiblyDestroyed() const {
  57. return K == UnlockedAndPossiblyDestroyed;
  58. }
  59. void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); }
  60. };
  61. class PthreadLockChecker : public Checker<check::PostCall, check::DeadSymbols,
  62. check::RegionChanges> {
  63. public:
  64. enum LockingSemantics { NotApplicable = 0, PthreadSemantics, XNUSemantics };
  65. enum CheckerKind {
  66. CK_PthreadLockChecker,
  67. CK_FuchsiaLockChecker,
  68. CK_C11LockChecker,
  69. CK_NumCheckKinds
  70. };
  71. DefaultBool ChecksEnabled[CK_NumCheckKinds];
  72. CheckerNameRef CheckNames[CK_NumCheckKinds];
  73. private:
  74. typedef void (PthreadLockChecker::*FnCheck)(const CallEvent &Call,
  75. CheckerContext &C,
  76. CheckerKind CheckKind) const;
  77. CallDescriptionMap<FnCheck> PThreadCallbacks = {
  78. // Init.
  79. {{"pthread_mutex_init", 2}, &PthreadLockChecker::InitAnyLock},
  80. // TODO: pthread_rwlock_init(2 arguments).
  81. // TODO: lck_mtx_init(3 arguments).
  82. // TODO: lck_mtx_alloc_init(2 arguments) => returns the mutex.
  83. // TODO: lck_rw_init(3 arguments).
  84. // TODO: lck_rw_alloc_init(2 arguments) => returns the mutex.
  85. // Acquire.
  86. {{"pthread_mutex_lock", 1}, &PthreadLockChecker::AcquirePthreadLock},
  87. {{"pthread_rwlock_rdlock", 1}, &PthreadLockChecker::AcquirePthreadLock},
  88. {{"pthread_rwlock_wrlock", 1}, &PthreadLockChecker::AcquirePthreadLock},
  89. {{"lck_mtx_lock", 1}, &PthreadLockChecker::AcquireXNULock},
  90. {{"lck_rw_lock_exclusive", 1}, &PthreadLockChecker::AcquireXNULock},
  91. {{"lck_rw_lock_shared", 1}, &PthreadLockChecker::AcquireXNULock},
  92. // Try.
  93. {{"pthread_mutex_trylock", 1}, &PthreadLockChecker::TryPthreadLock},
  94. {{"pthread_rwlock_tryrdlock", 1}, &PthreadLockChecker::TryPthreadLock},
  95. {{"pthread_rwlock_trywrlock", 1}, &PthreadLockChecker::TryPthreadLock},
  96. {{"lck_mtx_try_lock", 1}, &PthreadLockChecker::TryXNULock},
  97. {{"lck_rw_try_lock_exclusive", 1}, &PthreadLockChecker::TryXNULock},
  98. {{"lck_rw_try_lock_shared", 1}, &PthreadLockChecker::TryXNULock},
  99. // Release.
  100. {{"pthread_mutex_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
  101. {{"pthread_rwlock_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
  102. {{"lck_mtx_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
  103. {{"lck_rw_unlock_exclusive", 1}, &PthreadLockChecker::ReleaseAnyLock},
  104. {{"lck_rw_unlock_shared", 1}, &PthreadLockChecker::ReleaseAnyLock},
  105. {{"lck_rw_done", 1}, &PthreadLockChecker::ReleaseAnyLock},
  106. // Destroy.
  107. {{"pthread_mutex_destroy", 1}, &PthreadLockChecker::DestroyPthreadLock},
  108. {{"lck_mtx_destroy", 2}, &PthreadLockChecker::DestroyXNULock},
  109. // TODO: pthread_rwlock_destroy(1 argument).
  110. // TODO: lck_rw_destroy(2 arguments).
  111. };
  112. CallDescriptionMap<FnCheck> FuchsiaCallbacks = {
  113. // Init.
  114. {{"spin_lock_init", 1}, &PthreadLockChecker::InitAnyLock},
  115. // Acquire.
  116. {{"spin_lock", 1}, &PthreadLockChecker::AcquirePthreadLock},
  117. {{"spin_lock_save", 3}, &PthreadLockChecker::AcquirePthreadLock},
  118. {{"sync_mutex_lock", 1}, &PthreadLockChecker::AcquirePthreadLock},
  119. {{"sync_mutex_lock_with_waiter", 1},
  120. &PthreadLockChecker::AcquirePthreadLock},
  121. // Try.
  122. {{"spin_trylock", 1}, &PthreadLockChecker::TryFuchsiaLock},
  123. {{"sync_mutex_trylock", 1}, &PthreadLockChecker::TryFuchsiaLock},
  124. {{"sync_mutex_timedlock", 2}, &PthreadLockChecker::TryFuchsiaLock},
  125. // Release.
  126. {{"spin_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
  127. {{"spin_unlock_restore", 3}, &PthreadLockChecker::ReleaseAnyLock},
  128. {{"sync_mutex_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
  129. };
  130. CallDescriptionMap<FnCheck> C11Callbacks = {
  131. // Init.
  132. {{"mtx_init", 2}, &PthreadLockChecker::InitAnyLock},
  133. // Acquire.
  134. {{"mtx_lock", 1}, &PthreadLockChecker::AcquirePthreadLock},
  135. // Try.
  136. {{"mtx_trylock", 1}, &PthreadLockChecker::TryC11Lock},
  137. {{"mtx_timedlock", 2}, &PthreadLockChecker::TryC11Lock},
  138. // Release.
  139. {{"mtx_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
  140. // Destroy
  141. {{"mtx_destroy", 1}, &PthreadLockChecker::DestroyPthreadLock},
  142. };
  143. ProgramStateRef resolvePossiblyDestroyedMutex(ProgramStateRef state,
  144. const MemRegion *lockR,
  145. const SymbolRef *sym) const;
  146. void reportBug(CheckerContext &C, std::unique_ptr<BugType> BT[],
  147. const Expr *MtxExpr, CheckerKind CheckKind,
  148. StringRef Desc) const;
  149. // Init.
  150. void InitAnyLock(const CallEvent &Call, CheckerContext &C,
  151. CheckerKind CheckKind) const;
  152. void InitLockAux(const CallEvent &Call, CheckerContext &C,
  153. const Expr *MtxExpr, SVal MtxVal,
  154. CheckerKind CheckKind) const;
  155. // Lock, Try-lock.
  156. void AcquirePthreadLock(const CallEvent &Call, CheckerContext &C,
  157. CheckerKind CheckKind) const;
  158. void AcquireXNULock(const CallEvent &Call, CheckerContext &C,
  159. CheckerKind CheckKind) const;
  160. void TryPthreadLock(const CallEvent &Call, CheckerContext &C,
  161. CheckerKind CheckKind) const;
  162. void TryXNULock(const CallEvent &Call, CheckerContext &C,
  163. CheckerKind CheckKind) const;
  164. void TryFuchsiaLock(const CallEvent &Call, CheckerContext &C,
  165. CheckerKind CheckKind) const;
  166. void TryC11Lock(const CallEvent &Call, CheckerContext &C,
  167. CheckerKind CheckKind) const;
  168. void AcquireLockAux(const CallEvent &Call, CheckerContext &C,
  169. const Expr *MtxExpr, SVal MtxVal, bool IsTryLock,
  170. LockingSemantics Semantics, CheckerKind CheckKind) const;
  171. // Release.
  172. void ReleaseAnyLock(const CallEvent &Call, CheckerContext &C,
  173. CheckerKind CheckKind) const;
  174. void ReleaseLockAux(const CallEvent &Call, CheckerContext &C,
  175. const Expr *MtxExpr, SVal MtxVal,
  176. CheckerKind CheckKind) const;
  177. // Destroy.
  178. void DestroyPthreadLock(const CallEvent &Call, CheckerContext &C,
  179. CheckerKind CheckKind) const;
  180. void DestroyXNULock(const CallEvent &Call, CheckerContext &C,
  181. CheckerKind CheckKind) const;
  182. void DestroyLockAux(const CallEvent &Call, CheckerContext &C,
  183. const Expr *MtxExpr, SVal MtxVal,
  184. LockingSemantics Semantics, CheckerKind CheckKind) const;
  185. public:
  186. void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
  187. void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
  188. ProgramStateRef
  189. checkRegionChanges(ProgramStateRef State, const InvalidatedSymbols *Symbols,
  190. ArrayRef<const MemRegion *> ExplicitRegions,
  191. ArrayRef<const MemRegion *> Regions,
  192. const LocationContext *LCtx, const CallEvent *Call) const;
  193. void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
  194. const char *Sep) const override;
  195. private:
  196. mutable std::unique_ptr<BugType> BT_doublelock[CK_NumCheckKinds];
  197. mutable std::unique_ptr<BugType> BT_doubleunlock[CK_NumCheckKinds];
  198. mutable std::unique_ptr<BugType> BT_destroylock[CK_NumCheckKinds];
  199. mutable std::unique_ptr<BugType> BT_initlock[CK_NumCheckKinds];
  200. mutable std::unique_ptr<BugType> BT_lor[CK_NumCheckKinds];
  201. void initBugType(CheckerKind CheckKind) const {
  202. if (BT_doublelock[CheckKind])
  203. return;
  204. BT_doublelock[CheckKind].reset(
  205. new BugType{CheckNames[CheckKind], "Double locking", "Lock checker"});
  206. BT_doubleunlock[CheckKind].reset(
  207. new BugType{CheckNames[CheckKind], "Double unlocking", "Lock checker"});
  208. BT_destroylock[CheckKind].reset(new BugType{
  209. CheckNames[CheckKind], "Use destroyed lock", "Lock checker"});
  210. BT_initlock[CheckKind].reset(new BugType{
  211. CheckNames[CheckKind], "Init invalid lock", "Lock checker"});
  212. BT_lor[CheckKind].reset(new BugType{CheckNames[CheckKind],
  213. "Lock order reversal", "Lock checker"});
  214. }
  215. };
  216. } // end anonymous namespace
  217. // A stack of locks for tracking lock-unlock order.
  218. REGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *)
  219. // An entry for tracking lock states.
  220. REGISTER_MAP_WITH_PROGRAMSTATE(LockMap, const MemRegion *, LockState)
  221. // Return values for unresolved calls to pthread_mutex_destroy().
  222. REGISTER_MAP_WITH_PROGRAMSTATE(DestroyRetVal, const MemRegion *, SymbolRef)
  223. void PthreadLockChecker::checkPostCall(const CallEvent &Call,
  224. CheckerContext &C) const {
  225. // An additional umbrella check that all functions modeled by this checker
  226. // are global C functions.
  227. // TODO: Maybe make this the default behavior of CallDescription
  228. // with exactly one identifier?
  229. // FIXME: Try to handle cases when the implementation was inlined rather
  230. // than just giving up.
  231. if (!Call.isGlobalCFunction() || C.wasInlined)
  232. return;
  233. if (const FnCheck *Callback = PThreadCallbacks.lookup(Call))
  234. (this->**Callback)(Call, C, CK_PthreadLockChecker);
  235. else if (const FnCheck *Callback = FuchsiaCallbacks.lookup(Call))
  236. (this->**Callback)(Call, C, CK_FuchsiaLockChecker);
  237. else if (const FnCheck *Callback = C11Callbacks.lookup(Call))
  238. (this->**Callback)(Call, C, CK_C11LockChecker);
  239. }
  240. // When a lock is destroyed, in some semantics(like PthreadSemantics) we are not
  241. // sure if the destroy call has succeeded or failed, and the lock enters one of
  242. // the 'possibly destroyed' state. There is a short time frame for the
  243. // programmer to check the return value to see if the lock was successfully
  244. // destroyed. Before we model the next operation over that lock, we call this
  245. // function to see if the return value was checked by now and set the lock state
  246. // - either to destroyed state or back to its previous state.
  247. // In PthreadSemantics, pthread_mutex_destroy() returns zero if the lock is
  248. // successfully destroyed and it returns a non-zero value otherwise.
  249. ProgramStateRef PthreadLockChecker::resolvePossiblyDestroyedMutex(
  250. ProgramStateRef state, const MemRegion *lockR, const SymbolRef *sym) const {
  251. const LockState *lstate = state->get<LockMap>(lockR);
  252. // Existence in DestroyRetVal ensures existence in LockMap.
  253. // Existence in Destroyed also ensures that the lock state for lockR is either
  254. // UntouchedAndPossiblyDestroyed or UnlockedAndPossiblyDestroyed.
  255. assert(lstate->isUntouchedAndPossiblyDestroyed() ||
  256. lstate->isUnlockedAndPossiblyDestroyed());
  257. ConstraintManager &CMgr = state->getConstraintManager();
  258. ConditionTruthVal retZero = CMgr.isNull(state, *sym);
  259. if (retZero.isConstrainedFalse()) {
  260. if (lstate->isUntouchedAndPossiblyDestroyed())
  261. state = state->remove<LockMap>(lockR);
  262. else if (lstate->isUnlockedAndPossiblyDestroyed())
  263. state = state->set<LockMap>(lockR, LockState::getUnlocked());
  264. } else
  265. state = state->set<LockMap>(lockR, LockState::getDestroyed());
  266. // Removing the map entry (lockR, sym) from DestroyRetVal as the lock state is
  267. // now resolved.
  268. state = state->remove<DestroyRetVal>(lockR);
  269. return state;
  270. }
  271. void PthreadLockChecker::printState(raw_ostream &Out, ProgramStateRef State,
  272. const char *NL, const char *Sep) const {
  273. LockMapTy LM = State->get<LockMap>();
  274. if (!LM.isEmpty()) {
  275. Out << Sep << "Mutex states:" << NL;
  276. for (auto I : LM) {
  277. I.first->dumpToStream(Out);
  278. if (I.second.isLocked())
  279. Out << ": locked";
  280. else if (I.second.isUnlocked())
  281. Out << ": unlocked";
  282. else if (I.second.isDestroyed())
  283. Out << ": destroyed";
  284. else if (I.second.isUntouchedAndPossiblyDestroyed())
  285. Out << ": not tracked, possibly destroyed";
  286. else if (I.second.isUnlockedAndPossiblyDestroyed())
  287. Out << ": unlocked, possibly destroyed";
  288. Out << NL;
  289. }
  290. }
  291. LockSetTy LS = State->get<LockSet>();
  292. if (!LS.isEmpty()) {
  293. Out << Sep << "Mutex lock order:" << NL;
  294. for (auto I : LS) {
  295. I->dumpToStream(Out);
  296. Out << NL;
  297. }
  298. }
  299. DestroyRetValTy DRV = State->get<DestroyRetVal>();
  300. if (!DRV.isEmpty()) {
  301. Out << Sep << "Mutexes in unresolved possibly destroyed state:" << NL;
  302. for (auto I : DRV) {
  303. I.first->dumpToStream(Out);
  304. Out << ": ";
  305. I.second->dumpToStream(Out);
  306. Out << NL;
  307. }
  308. }
  309. }
  310. void PthreadLockChecker::AcquirePthreadLock(const CallEvent &Call,
  311. CheckerContext &C,
  312. CheckerKind CheckKind) const {
  313. AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), false,
  314. PthreadSemantics, CheckKind);
  315. }
  316. void PthreadLockChecker::AcquireXNULock(const CallEvent &Call,
  317. CheckerContext &C,
  318. CheckerKind CheckKind) const {
  319. AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), false,
  320. XNUSemantics, CheckKind);
  321. }
  322. void PthreadLockChecker::TryPthreadLock(const CallEvent &Call,
  323. CheckerContext &C,
  324. CheckerKind CheckKind) const {
  325. AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), true,
  326. PthreadSemantics, CheckKind);
  327. }
  328. void PthreadLockChecker::TryXNULock(const CallEvent &Call, CheckerContext &C,
  329. CheckerKind CheckKind) const {
  330. AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), true,
  331. PthreadSemantics, CheckKind);
  332. }
  333. void PthreadLockChecker::TryFuchsiaLock(const CallEvent &Call,
  334. CheckerContext &C,
  335. CheckerKind CheckKind) const {
  336. AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), true,
  337. PthreadSemantics, CheckKind);
  338. }
  339. void PthreadLockChecker::TryC11Lock(const CallEvent &Call, CheckerContext &C,
  340. CheckerKind CheckKind) const {
  341. AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), true,
  342. PthreadSemantics, CheckKind);
  343. }
  344. void PthreadLockChecker::AcquireLockAux(const CallEvent &Call,
  345. CheckerContext &C, const Expr *MtxExpr,
  346. SVal MtxVal, bool IsTryLock,
  347. enum LockingSemantics Semantics,
  348. CheckerKind CheckKind) const {
  349. if (!ChecksEnabled[CheckKind])
  350. return;
  351. const MemRegion *lockR = MtxVal.getAsRegion();
  352. if (!lockR)
  353. return;
  354. ProgramStateRef state = C.getState();
  355. const SymbolRef *sym = state->get<DestroyRetVal>(lockR);
  356. if (sym)
  357. state = resolvePossiblyDestroyedMutex(state, lockR, sym);
  358. if (const LockState *LState = state->get<LockMap>(lockR)) {
  359. if (LState->isLocked()) {
  360. reportBug(C, BT_doublelock, MtxExpr, CheckKind,
  361. "This lock has already been acquired");
  362. return;
  363. } else if (LState->isDestroyed()) {
  364. reportBug(C, BT_destroylock, MtxExpr, CheckKind,
  365. "This lock has already been destroyed");
  366. return;
  367. }
  368. }
  369. ProgramStateRef lockSucc = state;
  370. if (IsTryLock) {
  371. // Bifurcate the state, and allow a mode where the lock acquisition fails.
  372. SVal RetVal = Call.getReturnValue();
  373. if (auto DefinedRetVal = RetVal.getAs<DefinedSVal>()) {
  374. ProgramStateRef lockFail;
  375. switch (Semantics) {
  376. case PthreadSemantics:
  377. std::tie(lockFail, lockSucc) = state->assume(*DefinedRetVal);
  378. break;
  379. case XNUSemantics:
  380. std::tie(lockSucc, lockFail) = state->assume(*DefinedRetVal);
  381. break;
  382. default:
  383. llvm_unreachable("Unknown tryLock locking semantics");
  384. }
  385. assert(lockFail && lockSucc);
  386. C.addTransition(lockFail);
  387. }
  388. // We might want to handle the case when the mutex lock function was inlined
  389. // and returned an Unknown or Undefined value.
  390. } else if (Semantics == PthreadSemantics) {
  391. // Assume that the return value was 0.
  392. SVal RetVal = Call.getReturnValue();
  393. if (auto DefinedRetVal = RetVal.getAs<DefinedSVal>()) {
  394. // FIXME: If the lock function was inlined and returned true,
  395. // we need to behave sanely - at least generate sink.
  396. lockSucc = state->assume(*DefinedRetVal, false);
  397. assert(lockSucc);
  398. }
  399. // We might want to handle the case when the mutex lock function was inlined
  400. // and returned an Unknown or Undefined value.
  401. } else {
  402. // XNU locking semantics return void on non-try locks
  403. assert((Semantics == XNUSemantics) && "Unknown locking semantics");
  404. lockSucc = state;
  405. }
  406. // Record that the lock was acquired.
  407. lockSucc = lockSucc->add<LockSet>(lockR);
  408. lockSucc = lockSucc->set<LockMap>(lockR, LockState::getLocked());
  409. C.addTransition(lockSucc);
  410. }
  411. void PthreadLockChecker::ReleaseAnyLock(const CallEvent &Call,
  412. CheckerContext &C,
  413. CheckerKind CheckKind) const {
  414. ReleaseLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), CheckKind);
  415. }
  416. void PthreadLockChecker::ReleaseLockAux(const CallEvent &Call,
  417. CheckerContext &C, const Expr *MtxExpr,
  418. SVal MtxVal,
  419. CheckerKind CheckKind) const {
  420. if (!ChecksEnabled[CheckKind])
  421. return;
  422. const MemRegion *lockR = MtxVal.getAsRegion();
  423. if (!lockR)
  424. return;
  425. ProgramStateRef state = C.getState();
  426. const SymbolRef *sym = state->get<DestroyRetVal>(lockR);
  427. if (sym)
  428. state = resolvePossiblyDestroyedMutex(state, lockR, sym);
  429. if (const LockState *LState = state->get<LockMap>(lockR)) {
  430. if (LState->isUnlocked()) {
  431. reportBug(C, BT_doubleunlock, MtxExpr, CheckKind,
  432. "This lock has already been unlocked");
  433. return;
  434. } else if (LState->isDestroyed()) {
  435. reportBug(C, BT_destroylock, MtxExpr, CheckKind,
  436. "This lock has already been destroyed");
  437. return;
  438. }
  439. }
  440. LockSetTy LS = state->get<LockSet>();
  441. if (!LS.isEmpty()) {
  442. const MemRegion *firstLockR = LS.getHead();
  443. if (firstLockR != lockR) {
  444. reportBug(C, BT_lor, MtxExpr, CheckKind,
  445. "This was not the most recently acquired lock. Possible lock "
  446. "order reversal");
  447. return;
  448. }
  449. // Record that the lock was released.
  450. state = state->set<LockSet>(LS.getTail());
  451. }
  452. state = state->set<LockMap>(lockR, LockState::getUnlocked());
  453. C.addTransition(state);
  454. }
  455. void PthreadLockChecker::DestroyPthreadLock(const CallEvent &Call,
  456. CheckerContext &C,
  457. CheckerKind CheckKind) const {
  458. DestroyLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0),
  459. PthreadSemantics, CheckKind);
  460. }
  461. void PthreadLockChecker::DestroyXNULock(const CallEvent &Call,
  462. CheckerContext &C,
  463. CheckerKind CheckKind) const {
  464. DestroyLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), XNUSemantics,
  465. CheckKind);
  466. }
  467. void PthreadLockChecker::DestroyLockAux(const CallEvent &Call,
  468. CheckerContext &C, const Expr *MtxExpr,
  469. SVal MtxVal,
  470. enum LockingSemantics Semantics,
  471. CheckerKind CheckKind) const {
  472. if (!ChecksEnabled[CheckKind])
  473. return;
  474. const MemRegion *LockR = MtxVal.getAsRegion();
  475. if (!LockR)
  476. return;
  477. ProgramStateRef State = C.getState();
  478. const SymbolRef *sym = State->get<DestroyRetVal>(LockR);
  479. if (sym)
  480. State = resolvePossiblyDestroyedMutex(State, LockR, sym);
  481. const LockState *LState = State->get<LockMap>(LockR);
  482. // Checking the return value of the destroy method only in the case of
  483. // PthreadSemantics
  484. if (Semantics == PthreadSemantics) {
  485. if (!LState || LState->isUnlocked()) {
  486. SymbolRef sym = Call.getReturnValue().getAsSymbol();
  487. if (!sym) {
  488. State = State->remove<LockMap>(LockR);
  489. C.addTransition(State);
  490. return;
  491. }
  492. State = State->set<DestroyRetVal>(LockR, sym);
  493. if (LState && LState->isUnlocked())
  494. State = State->set<LockMap>(
  495. LockR, LockState::getUnlockedAndPossiblyDestroyed());
  496. else
  497. State = State->set<LockMap>(
  498. LockR, LockState::getUntouchedAndPossiblyDestroyed());
  499. C.addTransition(State);
  500. return;
  501. }
  502. } else {
  503. if (!LState || LState->isUnlocked()) {
  504. State = State->set<LockMap>(LockR, LockState::getDestroyed());
  505. C.addTransition(State);
  506. return;
  507. }
  508. }
  509. StringRef Message = LState->isLocked()
  510. ? "This lock is still locked"
  511. : "This lock has already been destroyed";
  512. reportBug(C, BT_destroylock, MtxExpr, CheckKind, Message);
  513. }
  514. void PthreadLockChecker::InitAnyLock(const CallEvent &Call, CheckerContext &C,
  515. CheckerKind CheckKind) const {
  516. InitLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), CheckKind);
  517. }
  518. void PthreadLockChecker::InitLockAux(const CallEvent &Call, CheckerContext &C,
  519. const Expr *MtxExpr, SVal MtxVal,
  520. CheckerKind CheckKind) const {
  521. if (!ChecksEnabled[CheckKind])
  522. return;
  523. const MemRegion *LockR = MtxVal.getAsRegion();
  524. if (!LockR)
  525. return;
  526. ProgramStateRef State = C.getState();
  527. const SymbolRef *sym = State->get<DestroyRetVal>(LockR);
  528. if (sym)
  529. State = resolvePossiblyDestroyedMutex(State, LockR, sym);
  530. const struct LockState *LState = State->get<LockMap>(LockR);
  531. if (!LState || LState->isDestroyed()) {
  532. State = State->set<LockMap>(LockR, LockState::getUnlocked());
  533. C.addTransition(State);
  534. return;
  535. }
  536. StringRef Message = LState->isLocked()
  537. ? "This lock is still being held"
  538. : "This lock has already been initialized";
  539. reportBug(C, BT_initlock, MtxExpr, CheckKind, Message);
  540. }
  541. void PthreadLockChecker::reportBug(CheckerContext &C,
  542. std::unique_ptr<BugType> BT[],
  543. const Expr *MtxExpr, CheckerKind CheckKind,
  544. StringRef Desc) const {
  545. ExplodedNode *N = C.generateErrorNode();
  546. if (!N)
  547. return;
  548. initBugType(CheckKind);
  549. auto Report =
  550. std::make_unique<PathSensitiveBugReport>(*BT[CheckKind], Desc, N);
  551. Report->addRange(MtxExpr->getSourceRange());
  552. C.emitReport(std::move(Report));
  553. }
  554. void PthreadLockChecker::checkDeadSymbols(SymbolReaper &SymReaper,
  555. CheckerContext &C) const {
  556. ProgramStateRef State = C.getState();
  557. for (auto I : State->get<DestroyRetVal>()) {
  558. // Once the return value symbol dies, no more checks can be performed
  559. // against it. See if the return value was checked before this point.
  560. // This would remove the symbol from the map as well.
  561. if (SymReaper.isDead(I.second))
  562. State = resolvePossiblyDestroyedMutex(State, I.first, &I.second);
  563. }
  564. for (auto I : State->get<LockMap>()) {
  565. // Stop tracking dead mutex regions as well.
  566. if (!SymReaper.isLiveRegion(I.first)) {
  567. State = State->remove<LockMap>(I.first);
  568. State = State->remove<DestroyRetVal>(I.first);
  569. }
  570. }
  571. // TODO: We probably need to clean up the lock stack as well.
  572. // It is tricky though: even if the mutex cannot be unlocked anymore,
  573. // it can still participate in lock order reversal resolution.
  574. C.addTransition(State);
  575. }
  576. ProgramStateRef PthreadLockChecker::checkRegionChanges(
  577. ProgramStateRef State, const InvalidatedSymbols *Symbols,
  578. ArrayRef<const MemRegion *> ExplicitRegions,
  579. ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
  580. const CallEvent *Call) const {
  581. bool IsLibraryFunction = false;
  582. if (Call && Call->isGlobalCFunction()) {
  583. // Avoid invalidating mutex state when a known supported function is called.
  584. if (PThreadCallbacks.lookup(*Call) || FuchsiaCallbacks.lookup(*Call) ||
  585. C11Callbacks.lookup(*Call))
  586. return State;
  587. if (Call->isInSystemHeader())
  588. IsLibraryFunction = true;
  589. }
  590. for (auto R : Regions) {
  591. // We assume that system library function wouldn't touch the mutex unless
  592. // it takes the mutex explicitly as an argument.
  593. // FIXME: This is a bit quadratic.
  594. if (IsLibraryFunction && !llvm::is_contained(ExplicitRegions, R))
  595. continue;
  596. State = State->remove<LockMap>(R);
  597. State = State->remove<DestroyRetVal>(R);
  598. // TODO: We need to invalidate the lock stack as well. This is tricky
  599. // to implement correctly and efficiently though, because the effects
  600. // of mutex escapes on lock order may be fairly varied.
  601. }
  602. return State;
  603. }
  604. void ento::registerPthreadLockBase(CheckerManager &mgr) {
  605. mgr.registerChecker<PthreadLockChecker>();
  606. }
  607. bool ento::shouldRegisterPthreadLockBase(const CheckerManager &mgr) { return true; }
  608. #define REGISTER_CHECKER(name) \
  609. void ento::register##name(CheckerManager &mgr) { \
  610. PthreadLockChecker *checker = mgr.getChecker<PthreadLockChecker>(); \
  611. checker->ChecksEnabled[PthreadLockChecker::CK_##name] = true; \
  612. checker->CheckNames[PthreadLockChecker::CK_##name] = \
  613. mgr.getCurrentCheckerName(); \
  614. } \
  615. \
  616. bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
  617. REGISTER_CHECKER(PthreadLockChecker)
  618. REGISTER_CHECKER(FuchsiaLockChecker)
  619. REGISTER_CHECKER(C11LockChecker)