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