25#include "llvm/ADT/STLExtras.h"
26#include "llvm/ADT/StringRef.h"
40 StringRef MsgForNamed,
41 StringRef MsgForUnnamed) {
43 [R, Named = MsgForNamed.str(), Unnamed = MsgForUnnamed.str()](
45 if (!isLockRelevant(R, BR))
47 std::string Name = R->getDescriptiveName();
51 OS << Named << Name <<
" here";
62 UntouchedAndPossiblyDestroyed,
63 UnlockedAndPossiblyDestroyed
67 LockState(Kind K) : K(K) {}
70 static LockState getLocked() {
return LockState(Locked); }
71 static LockState getUnlocked() {
return LockState(Unlocked); }
72 static LockState getDestroyed() {
return LockState(Destroyed); }
73 static LockState getUntouchedAndPossiblyDestroyed() {
74 return LockState(UntouchedAndPossiblyDestroyed);
76 static LockState getUnlockedAndPossiblyDestroyed() {
77 return LockState(UnlockedAndPossiblyDestroyed);
80 bool operator==(
const LockState &
X)
const {
return K ==
X.K; }
82 bool isLocked()
const {
return K == Locked; }
83 bool isUnlocked()
const {
return K == Unlocked; }
84 bool isDestroyed()
const {
return K == Destroyed; }
85 bool isUntouchedAndPossiblyDestroyed()
const {
86 return K == UntouchedAndPossiblyDestroyed;
88 bool isUnlockedAndPossiblyDestroyed()
const {
89 return K == UnlockedAndPossiblyDestroyed;
92 void Profile(llvm::FoldingSetNodeID &ID)
const {
ID.AddInteger(K); }
95class PthreadLockChecker :
public Checker<check::PostCall, check::DeadSymbols,
96 check::RegionChanges> {
98 enum LockingSemantics { NotApplicable = 0, PthreadSemantics, XNUSemantics };
100 CK_PthreadLockChecker,
101 CK_FuchsiaLockChecker,
105 bool ChecksEnabled[CK_NumCheckKinds] = {
false};
106 CheckerNameRef CheckNames[CK_NumCheckKinds];
107 bool WarnOnLockOrderReversal =
false;
110 typedef void (PthreadLockChecker::*FnCheck)(
const CallEvent &
Call,
112 CheckerKind CheckKind)
const;
113 CallDescriptionMap<FnCheck> PThreadCallbacks = {
115 {{CDM::CLibrary, {
"pthread_mutex_init"}, 2},
116 &PthreadLockChecker::InitAnyLock},
124 {{CDM::CLibrary, {
"pthread_mutex_lock"}, 1},
125 &PthreadLockChecker::AcquirePthreadLock},
126 {{CDM::CLibrary, {
"pthread_rwlock_rdlock"}, 1},
127 &PthreadLockChecker::AcquirePthreadLock},
128 {{CDM::CLibrary, {
"pthread_rwlock_wrlock"}, 1},
129 &PthreadLockChecker::AcquirePthreadLock},
130 {{CDM::CLibrary, {
"lck_mtx_lock"}, 1},
131 &PthreadLockChecker::AcquireXNULock},
132 {{CDM::CLibrary, {
"lck_rw_lock_exclusive"}, 1},
133 &PthreadLockChecker::AcquireXNULock},
134 {{CDM::CLibrary, {
"lck_rw_lock_shared"}, 1},
135 &PthreadLockChecker::AcquireXNULock},
138 {{CDM::CLibrary, {
"pthread_mutex_trylock"}, 1},
139 &PthreadLockChecker::TryPthreadLock},
140 {{CDM::CLibrary, {
"pthread_rwlock_tryrdlock"}, 1},
141 &PthreadLockChecker::TryPthreadLock},
142 {{CDM::CLibrary, {
"pthread_rwlock_trywrlock"}, 1},
143 &PthreadLockChecker::TryPthreadLock},
144 {{CDM::CLibrary, {
"lck_mtx_try_lock"}, 1},
145 &PthreadLockChecker::TryXNULock},
146 {{CDM::CLibrary, {
"lck_rw_try_lock_exclusive"}, 1},
147 &PthreadLockChecker::TryXNULock},
148 {{CDM::CLibrary, {
"lck_rw_try_lock_shared"}, 1},
149 &PthreadLockChecker::TryXNULock},
152 {{CDM::CLibrary, {
"pthread_mutex_unlock"}, 1},
153 &PthreadLockChecker::ReleaseAnyLock},
154 {{CDM::CLibrary, {
"pthread_rwlock_unlock"}, 1},
155 &PthreadLockChecker::ReleaseAnyLock},
156 {{CDM::CLibrary, {
"lck_mtx_unlock"}, 1},
157 &PthreadLockChecker::ReleaseAnyLock},
158 {{CDM::CLibrary, {
"lck_rw_unlock_exclusive"}, 1},
159 &PthreadLockChecker::ReleaseAnyLock},
160 {{CDM::CLibrary, {
"lck_rw_unlock_shared"}, 1},
161 &PthreadLockChecker::ReleaseAnyLock},
162 {{CDM::CLibrary, {
"lck_rw_done"}, 1},
163 &PthreadLockChecker::ReleaseAnyLock},
166 {{CDM::CLibrary, {
"pthread_mutex_destroy"}, 1},
167 &PthreadLockChecker::DestroyPthreadLock},
168 {{CDM::CLibrary, {
"lck_mtx_destroy"}, 2},
169 &PthreadLockChecker::DestroyXNULock},
174 CallDescriptionMap<FnCheck> FuchsiaCallbacks = {
176 {{CDM::CLibrary, {
"spin_lock_init"}, 1},
177 &PthreadLockChecker::InitAnyLock},
180 {{CDM::CLibrary, {
"spin_lock"}, 1},
181 &PthreadLockChecker::AcquirePthreadLock},
182 {{CDM::CLibrary, {
"spin_lock_save"}, 3},
183 &PthreadLockChecker::AcquirePthreadLock},
184 {{CDM::CLibrary, {
"sync_mutex_lock"}, 1},
185 &PthreadLockChecker::AcquirePthreadLock},
186 {{CDM::CLibrary, {
"sync_mutex_lock_with_waiter"}, 1},
187 &PthreadLockChecker::AcquirePthreadLock},
190 {{CDM::CLibrary, {
"spin_trylock"}, 1},
191 &PthreadLockChecker::TryFuchsiaLock},
192 {{CDM::CLibrary, {
"sync_mutex_trylock"}, 1},
193 &PthreadLockChecker::TryFuchsiaLock},
194 {{CDM::CLibrary, {
"sync_mutex_timedlock"}, 2},
195 &PthreadLockChecker::TryFuchsiaLock},
198 {{CDM::CLibrary, {
"spin_unlock"}, 1},
199 &PthreadLockChecker::ReleaseAnyLock},
200 {{CDM::CLibrary, {
"spin_unlock_restore"}, 3},
201 &PthreadLockChecker::ReleaseAnyLock},
202 {{CDM::CLibrary, {
"sync_mutex_unlock"}, 1},
203 &PthreadLockChecker::ReleaseAnyLock},
206 CallDescriptionMap<FnCheck> C11Callbacks = {
208 {{CDM::CLibrary, {
"mtx_init"}, 2}, &PthreadLockChecker::InitAnyLock},
211 {{CDM::CLibrary, {
"mtx_lock"}, 1},
212 &PthreadLockChecker::AcquirePthreadLock},
215 {{CDM::CLibrary, {
"mtx_trylock"}, 1}, &PthreadLockChecker::TryC11Lock},
216 {{CDM::CLibrary, {
"mtx_timedlock"}, 2}, &PthreadLockChecker::TryC11Lock},
219 {{CDM::CLibrary, {
"mtx_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
222 {{CDM::CLibrary, {
"mtx_destroy"}, 1},
223 &PthreadLockChecker::DestroyPthreadLock},
227 const MemRegion *lockR,
229 void reportBug(CheckerContext &
C, std::unique_ptr<BugType> BT[],
230 const Expr *MtxExpr,
const MemRegion *MtxRegion,
231 CheckerKind CheckKind, StringRef Desc,
232 const MemRegion *ExtraInteresting =
nullptr)
const;
235 void InitAnyLock(
const CallEvent &
Call, CheckerContext &
C,
236 CheckerKind CheckKind)
const;
237 void InitLockAux(
const CallEvent &
Call, CheckerContext &
C,
238 const Expr *MtxExpr, SVal MtxVal,
239 CheckerKind CheckKind)
const;
242 void AcquirePthreadLock(
const CallEvent &
Call, CheckerContext &
C,
243 CheckerKind CheckKind)
const;
244 void AcquireXNULock(
const CallEvent &
Call, CheckerContext &
C,
245 CheckerKind CheckKind)
const;
246 void TryPthreadLock(
const CallEvent &
Call, CheckerContext &
C,
247 CheckerKind CheckKind)
const;
248 void TryXNULock(
const CallEvent &
Call, CheckerContext &
C,
249 CheckerKind CheckKind)
const;
250 void TryFuchsiaLock(
const CallEvent &
Call, CheckerContext &
C,
251 CheckerKind CheckKind)
const;
252 void TryC11Lock(
const CallEvent &
Call, CheckerContext &
C,
253 CheckerKind CheckKind)
const;
254 void AcquireLockAux(
const CallEvent &
Call, CheckerContext &
C,
255 const Expr *MtxExpr, SVal MtxVal,
bool IsTryLock,
256 LockingSemantics Semantics, CheckerKind CheckKind)
const;
259 void ReleaseAnyLock(
const CallEvent &
Call, CheckerContext &
C,
260 CheckerKind CheckKind)
const;
261 void ReleaseLockAux(
const CallEvent &
Call, CheckerContext &
C,
262 const Expr *MtxExpr, SVal MtxVal,
263 CheckerKind CheckKind)
const;
266 void DestroyPthreadLock(
const CallEvent &
Call, CheckerContext &
C,
267 CheckerKind CheckKind)
const;
268 void DestroyXNULock(
const CallEvent &
Call, CheckerContext &
C,
269 CheckerKind CheckKind)
const;
270 void DestroyLockAux(
const CallEvent &
Call, CheckerContext &
C,
271 const Expr *MtxExpr, SVal MtxVal,
272 LockingSemantics Semantics, CheckerKind CheckKind)
const;
275 void checkPostCall(
const CallEvent &
Call, CheckerContext &
C)
const;
276 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &
C)
const;
279 ArrayRef<const MemRegion *> ExplicitRegions,
280 ArrayRef<const MemRegion *> Regions,
const StackFrame *SF,
281 const CallEvent *
Call)
const;
282 void printState(raw_ostream &Out,
ProgramStateRef State,
const char *NL,
283 const char *Sep)
const override;
286 mutable std::unique_ptr<BugType> BT_doublelock[CK_NumCheckKinds];
287 mutable std::unique_ptr<BugType> BT_doubleunlock[CK_NumCheckKinds];
288 mutable std::unique_ptr<BugType> BT_destroylock[CK_NumCheckKinds];
289 mutable std::unique_ptr<BugType> BT_initlock[CK_NumCheckKinds];
290 mutable std::unique_ptr<BugType> BT_lor[CK_NumCheckKinds];
292 void initBugType(CheckerKind CheckKind)
const {
293 if (BT_doublelock[CheckKind])
295 BT_doublelock[CheckKind].reset(
new BugType{
297 BT_doubleunlock[CheckKind].reset(
new BugType{
299 BT_destroylock[CheckKind].reset(
new BugType{
301 BT_initlock[CheckKind].reset(
new BugType{
303 BT_lor[CheckKind].reset(
new BugType{
325 if (
const FnCheck *Callback = PThreadCallbacks.lookup(
Call))
326 (this->**Callback)(
Call,
C, CK_PthreadLockChecker);
327 else if (
const FnCheck *Callback = FuchsiaCallbacks.
lookup(
Call))
328 (this->**Callback)(
Call,
C, CK_FuchsiaLockChecker);
329 else if (
const FnCheck *Callback = C11Callbacks.
lookup(
Call))
330 (this->**Callback)(
Call,
C, CK_C11LockChecker);
345 const LockState *lstate = state->get<LockMap>(lockR);
350 assert(lstate->isUntouchedAndPossiblyDestroyed() ||
351 lstate->isUnlockedAndPossiblyDestroyed());
353 ConstraintManager &CMgr = state->getConstraintManager();
354 ConditionTruthVal retZero = CMgr.
isNull(state, *sym);
356 if (lstate->isUntouchedAndPossiblyDestroyed())
357 state = state->remove<LockMap>(lockR);
358 else if (lstate->isUnlockedAndPossiblyDestroyed())
359 state = state->set<LockMap>(lockR, LockState::getUnlocked());
361 state = state->set<LockMap>(lockR, LockState::getDestroyed());
365 state = state->remove<DestroyRetVal>(lockR);
369void PthreadLockChecker::printState(raw_ostream &Out,
ProgramStateRef State,
370 const char *NL,
const char *Sep)
const {
371 LockMapTy LM = State->get<LockMap>();
373 Out << Sep <<
"Mutex states:" << NL;
375 I.first->dumpToStream(Out);
376 if (I.second.isLocked())
378 else if (I.second.isUnlocked())
380 else if (I.second.isDestroyed())
381 Out <<
": destroyed";
382 else if (I.second.isUntouchedAndPossiblyDestroyed())
383 Out <<
": not tracked, possibly destroyed";
384 else if (I.second.isUnlockedAndPossiblyDestroyed())
385 Out <<
": unlocked, possibly destroyed";
390 LockSetTy LS = State->get<LockSet>();
392 Out << Sep <<
"Mutex lock order:" << NL;
394 I->dumpToStream(Out);
399 DestroyRetValTy DRV = State->get<DestroyRetVal>();
400 if (!DRV.isEmpty()) {
401 Out << Sep <<
"Mutexes in unresolved possibly destroyed state:" << NL;
403 I.first->dumpToStream(Out);
405 I.second->dumpToStream(Out);
411void PthreadLockChecker::AcquirePthreadLock(
const CallEvent &
Call,
413 CheckerKind CheckKind)
const {
414 AcquireLockAux(
Call,
C,
Call.getArgExpr(0),
Call.getArgSVal(0),
false,
415 PthreadSemantics, CheckKind);
418void PthreadLockChecker::AcquireXNULock(
const CallEvent &
Call,
420 CheckerKind CheckKind)
const {
421 AcquireLockAux(
Call,
C,
Call.getArgExpr(0),
Call.getArgSVal(0),
false,
422 XNUSemantics, CheckKind);
425void PthreadLockChecker::TryPthreadLock(
const CallEvent &
Call,
427 CheckerKind CheckKind)
const {
428 AcquireLockAux(
Call,
C,
Call.getArgExpr(0),
Call.getArgSVal(0),
true,
429 PthreadSemantics, CheckKind);
432void PthreadLockChecker::TryXNULock(
const CallEvent &
Call, CheckerContext &
C,
433 CheckerKind CheckKind)
const {
434 AcquireLockAux(
Call,
C,
Call.getArgExpr(0),
Call.getArgSVal(0),
true,
435 PthreadSemantics, CheckKind);
438void PthreadLockChecker::TryFuchsiaLock(
const CallEvent &
Call,
440 CheckerKind CheckKind)
const {
441 AcquireLockAux(
Call,
C,
Call.getArgExpr(0),
Call.getArgSVal(0),
true,
442 PthreadSemantics, CheckKind);
445void PthreadLockChecker::TryC11Lock(
const CallEvent &
Call, CheckerContext &
C,
446 CheckerKind CheckKind)
const {
447 AcquireLockAux(
Call,
C,
Call.getArgExpr(0),
Call.getArgSVal(0),
true,
448 PthreadSemantics, CheckKind);
451void PthreadLockChecker::AcquireLockAux(
const CallEvent &
Call,
452 CheckerContext &
C,
const Expr *MtxExpr,
453 SVal MtxVal,
bool IsTryLock,
454 enum LockingSemantics Semantics,
455 CheckerKind CheckKind)
const {
456 if (!ChecksEnabled[CheckKind])
464 const SymbolRef *sym = state->get<DestroyRetVal>(lockR);
466 state = resolvePossiblyDestroyedMutex(state, lockR, sym);
468 if (
const LockState *LState = state->get<LockMap>(lockR)) {
469 if (LState->isLocked()) {
470 reportBug(
C, BT_doublelock, MtxExpr, lockR, CheckKind,
471 "This lock has already been acquired");
473 }
else if (LState->isDestroyed()) {
474 reportBug(
C, BT_destroylock, MtxExpr, lockR, CheckKind,
475 "This lock has already been destroyed");
483 SVal RetVal =
Call.getReturnValue();
484 if (
auto DefinedRetVal = RetVal.
getAs<DefinedSVal>()) {
487 case PthreadSemantics:
488 std::tie(lockFail, lockSucc) = state->assume(*DefinedRetVal);
491 std::tie(lockSucc, lockFail) = state->assume(*DefinedRetVal);
494 llvm_unreachable(
"Unknown tryLock locking semantics");
496 assert(lockFail && lockSucc);
497 C.addTransition(lockFail);
501 }
else if (Semantics == PthreadSemantics) {
503 SVal RetVal =
Call.getReturnValue();
504 if (
auto DefinedRetVal = RetVal.
getAs<DefinedSVal>()) {
507 lockSucc = state->assume(*DefinedRetVal,
false);
514 assert((Semantics == XNUSemantics) &&
"Unknown locking semantics");
519 lockSucc = lockSucc->add<LockSet>(lockR);
520 lockSucc = lockSucc->set<LockMap>(lockR, LockState::getLocked());
521 C.addTransition(lockSucc,
525void PthreadLockChecker::ReleaseAnyLock(
const CallEvent &
Call,
527 CheckerKind CheckKind)
const {
528 ReleaseLockAux(
Call,
C,
Call.getArgExpr(0),
Call.getArgSVal(0), CheckKind);
531void PthreadLockChecker::ReleaseLockAux(
const CallEvent &
Call,
532 CheckerContext &
C,
const Expr *MtxExpr,
534 CheckerKind CheckKind)
const {
535 if (!ChecksEnabled[CheckKind])
543 const SymbolRef *sym = state->get<DestroyRetVal>(lockR);
545 state = resolvePossiblyDestroyedMutex(state, lockR, sym);
547 if (
const LockState *LState = state->get<LockMap>(lockR)) {
548 if (LState->isUnlocked()) {
549 reportBug(
C, BT_doubleunlock, MtxExpr, lockR, CheckKind,
550 "This lock has already been unlocked");
552 }
else if (LState->isDestroyed()) {
553 reportBug(
C, BT_destroylock, MtxExpr, lockR, CheckKind,
554 "This lock has already been destroyed");
559 LockSetTy LS = state->get<LockSet>();
562 if (WarnOnLockOrderReversal && LS.getHead() != lockR) {
563 reportBug(
C, BT_lor, MtxExpr, lockR, CheckKind,
564 "This was not the most recently acquired lock. Possible lock "
570 auto &Factory = state->get_context<LockSet>();
571 llvm::ImmutableList<const MemRegion *> NewLS = Factory.getEmptyList();
572 for (
const MemRegion *LockReg :
573 llvm::make_filter_range(LS, llvm::not_equal_to(lockR))) {
574 NewLS = Factory.add(LockReg, NewLS);
576 state = state->set<LockSet>(NewLS);
579 state = state->set<LockMap>(lockR, LockState::getUnlocked());
584void PthreadLockChecker::DestroyPthreadLock(
const CallEvent &
Call,
586 CheckerKind CheckKind)
const {
587 DestroyLockAux(
Call,
C,
Call.getArgExpr(0),
Call.getArgSVal(0),
588 PthreadSemantics, CheckKind);
591void PthreadLockChecker::DestroyXNULock(
const CallEvent &
Call,
593 CheckerKind CheckKind)
const {
594 DestroyLockAux(
Call,
C,
Call.getArgExpr(0),
Call.getArgSVal(0), XNUSemantics,
598void PthreadLockChecker::DestroyLockAux(
const CallEvent &
Call,
599 CheckerContext &
C,
const Expr *MtxExpr,
601 enum LockingSemantics Semantics,
602 CheckerKind CheckKind)
const {
603 if (!ChecksEnabled[CheckKind])
612 const SymbolRef *sym = State->get<DestroyRetVal>(LockR);
614 State = resolvePossiblyDestroyedMutex(State, LockR, sym);
616 const LockState *LState = State->get<LockMap>(LockR);
619 if (Semantics == PthreadSemantics) {
620 if (!LState || LState->isUnlocked()) {
623 State = State->remove<LockMap>(LockR);
625 "Mutex destroyed here"));
628 State = State->set<DestroyRetVal>(LockR, sym);
629 if (LState && LState->isUnlocked())
630 State = State->set<LockMap>(
631 LockR, LockState::getUnlockedAndPossiblyDestroyed());
633 State = State->set<LockMap>(
634 LockR, LockState::getUntouchedAndPossiblyDestroyed());
636 "Mutex destroyed here"));
640 if (!LState || LState->isUnlocked()) {
641 State = State->set<LockMap>(LockR, LockState::getDestroyed());
643 "Mutex destroyed here"));
648 StringRef
Message = LState->isLocked()
649 ?
"This lock is still locked"
650 :
"This lock has already been destroyed";
652 reportBug(
C, BT_destroylock, MtxExpr, LockR, CheckKind, Message);
655void PthreadLockChecker::InitAnyLock(
const CallEvent &
Call, CheckerContext &
C,
656 CheckerKind CheckKind)
const {
657 InitLockAux(
Call,
C,
Call.getArgExpr(0),
Call.getArgSVal(0), CheckKind);
660void PthreadLockChecker::InitLockAux(
const CallEvent &
Call, CheckerContext &
C,
661 const Expr *MtxExpr, SVal MtxVal,
662 CheckerKind CheckKind)
const {
663 if (!ChecksEnabled[CheckKind])
672 const SymbolRef *sym = State->get<DestroyRetVal>(LockR);
674 State = resolvePossiblyDestroyedMutex(State, LockR, sym);
676 const struct LockState *LState = State->get<LockMap>(LockR);
677 if (!LState || LState->isDestroyed()) {
678 State = State->set<LockMap>(LockR, LockState::getUnlocked());
680 "Mutex initialized here"));
684 StringRef
Message = LState->isLocked()
685 ?
"This lock is still being held"
686 :
"This lock has already been initialized";
688 reportBug(
C, BT_initlock, MtxExpr, LockR, CheckKind, Message);
691void PthreadLockChecker::reportBug(CheckerContext &
C,
692 std::unique_ptr<BugType> BT[],
694 const MemRegion *MtxRegion,
695 CheckerKind CheckKind, StringRef Desc,
696 const MemRegion *ExtraInteresting)
const {
697 ExplodedNode *N =
C.generateErrorNode();
700 initBugType(CheckKind);
702 std::make_unique<PathSensitiveBugReport>(*BT[CheckKind], Desc, N);
705 Report->markInteresting(MtxRegion);
706 if (ExtraInteresting)
707 Report->markInteresting(ExtraInteresting);
708 C.emitReport(std::move(
Report));
711void PthreadLockChecker::checkDeadSymbols(SymbolReaper &SymReaper,
712 CheckerContext &
C)
const {
715 for (
auto I : State->get<DestroyRetVal>()) {
719 if (SymReaper.
isDead(I.second))
720 State = resolvePossiblyDestroyedMutex(State, I.first, &I.second);
723 for (
auto I : State->get<LockMap>()) {
726 State = State->remove<LockMap>(I.first);
727 State = State->remove<DestroyRetVal>(I.first);
735 C.addTransition(State);
740 ArrayRef<const MemRegion *> ExplicitRegions,
741 ArrayRef<const MemRegion *> Regions,
const StackFrame *SF,
742 const CallEvent *
Call)
const {
744 bool IsLibraryFunction =
false;
745 if (
Call &&
Call->isGlobalCFunction()) {
747 if (PThreadCallbacks.lookup(*
Call) || FuchsiaCallbacks.
lookup(*
Call) ||
751 if (
Call->isInSystemHeader())
752 IsLibraryFunction =
true;
755 for (
auto R : Regions) {
759 if (IsLibraryFunction && !llvm::is_contained(ExplicitRegions, R))
762 State = State->remove<LockMap>(
R);
763 State = State->remove<DestroyRetVal>(
R);
773void ento::registerPthreadLockBase(CheckerManager &mgr) {
777bool ento::shouldRegisterPthreadLockBase(
const CheckerManager &mgr) {
return true; }
779#define REGISTER_CHECKER(name) \
780 void ento::register##name(CheckerManager &mgr) { \
781 PthreadLockChecker *checker = mgr.getChecker<PthreadLockChecker>(); \
782 checker->ChecksEnabled[PthreadLockChecker::CK_##name] = true; \
783 checker->CheckNames[PthreadLockChecker::CK_##name] = \
784 mgr.getCurrentCheckerName(); \
787 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
792#undef REGISTER_CHECKER
796 Checker->ChecksEnabled[PthreadLockChecker::CK_PthreadLockChecker] =
true;
797 Checker->CheckNames[PthreadLockChecker::CK_PthreadLockChecker] =
799 Checker->WarnOnLockOrderReversal =
804bool ento::shouldRegisterPthreadLockChecker(
const CheckerManager &) {
#define REGISTER_CHECKER(name)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_LIST_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable list type NameTy, suitable for placement into the ProgramState.
static bool isLockRelevant(const MemRegion *R, const PathSensitiveBugReport &BR)
static const NoteTag * createMutexNote(CheckerContext &C, const MemRegion *R, StringRef MsgForNamed, StringRef MsgForUnnamed)
constexpr llvm::StringRef LOCK_CHECKER_CATEGORY
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const BugType & getBugType() const
StringRef getCategory() const
const T * lookup(const CallEvent &Call) const
Represents an abstract call to a function or method along a particular path.
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
CheckerNameRef getCurrentCheckerName() const
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
Simple checker classes that implement one frontend (i.e.
bool isConstrainedFalse() const
Return true if the constraint is perfectly constrained to 'false'.
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym)
Convenience method to query the state to see if a symbol is null or not null, or if neither assumptio...
MemRegion - The root abstract class for all memory regions.
The tag upon which the TagVisitor reacts.
bool isInteresting(SymbolRef sym) const
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
const MemRegion * getAsRegion() const
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
bool isLiveRegion(const MemRegion *region)
llvm::DenseSet< SymbolRef > InvalidatedSymbols
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
The JSON file list parser is used to communicate input to InstallAPI.
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)