10b57cec5SDimitry Andric //===--- PthreadLockChecker.cpp - Check for locking problems ---*- C++ -*--===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 9*5ffd83dbSDimitry Andric // This file defines: 10*5ffd83dbSDimitry Andric // * PthreadLockChecker, a simple lock -> unlock checker. 11*5ffd83dbSDimitry Andric // Which also checks for XNU locks, which behave similarly enough to share 12*5ffd83dbSDimitry Andric // code. 13*5ffd83dbSDimitry Andric // * FuchsiaLocksChecker, which is also rather similar. 14*5ffd83dbSDimitry Andric // * C11LockChecker which also closely follows Pthread semantics. 15*5ffd83dbSDimitry Andric // 16*5ffd83dbSDimitry Andric // TODO: Path notes. 170b57cec5SDimitry Andric // 180b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 210b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 220b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 230b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h" 24*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 250b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric using namespace clang; 280b57cec5SDimitry Andric using namespace ento; 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric namespace { 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric struct LockState { 330b57cec5SDimitry Andric enum Kind { 340b57cec5SDimitry Andric Destroyed, 350b57cec5SDimitry Andric Locked, 360b57cec5SDimitry Andric Unlocked, 370b57cec5SDimitry Andric UntouchedAndPossiblyDestroyed, 380b57cec5SDimitry Andric UnlockedAndPossiblyDestroyed 390b57cec5SDimitry Andric } K; 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric private: 420b57cec5SDimitry Andric LockState(Kind K) : K(K) {} 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric public: 450b57cec5SDimitry Andric static LockState getLocked() { return LockState(Locked); } 460b57cec5SDimitry Andric static LockState getUnlocked() { return LockState(Unlocked); } 470b57cec5SDimitry Andric static LockState getDestroyed() { return LockState(Destroyed); } 480b57cec5SDimitry Andric static LockState getUntouchedAndPossiblyDestroyed() { 490b57cec5SDimitry Andric return LockState(UntouchedAndPossiblyDestroyed); 500b57cec5SDimitry Andric } 510b57cec5SDimitry Andric static LockState getUnlockedAndPossiblyDestroyed() { 520b57cec5SDimitry Andric return LockState(UnlockedAndPossiblyDestroyed); 530b57cec5SDimitry Andric } 540b57cec5SDimitry Andric 55*5ffd83dbSDimitry Andric bool operator==(const LockState &X) const { return K == X.K; } 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric bool isLocked() const { return K == Locked; } 580b57cec5SDimitry Andric bool isUnlocked() const { return K == Unlocked; } 590b57cec5SDimitry Andric bool isDestroyed() const { return K == Destroyed; } 600b57cec5SDimitry Andric bool isUntouchedAndPossiblyDestroyed() const { 610b57cec5SDimitry Andric return K == UntouchedAndPossiblyDestroyed; 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric bool isUnlockedAndPossiblyDestroyed() const { 640b57cec5SDimitry Andric return K == UnlockedAndPossiblyDestroyed; 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric 67*5ffd83dbSDimitry Andric void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); } 680b57cec5SDimitry Andric }; 690b57cec5SDimitry Andric 70*5ffd83dbSDimitry Andric class PthreadLockChecker : public Checker<check::PostCall, check::DeadSymbols, 71*5ffd83dbSDimitry Andric check::RegionChanges> { 720b57cec5SDimitry Andric public: 73*5ffd83dbSDimitry Andric enum LockingSemantics { NotApplicable = 0, PthreadSemantics, XNUSemantics }; 74*5ffd83dbSDimitry Andric enum CheckerKind { 75*5ffd83dbSDimitry Andric CK_PthreadLockChecker, 76*5ffd83dbSDimitry Andric CK_FuchsiaLockChecker, 77*5ffd83dbSDimitry Andric CK_C11LockChecker, 78*5ffd83dbSDimitry Andric CK_NumCheckKinds 79*5ffd83dbSDimitry Andric }; 80*5ffd83dbSDimitry Andric DefaultBool ChecksEnabled[CK_NumCheckKinds]; 81*5ffd83dbSDimitry Andric CheckerNameRef CheckNames[CK_NumCheckKinds]; 820b57cec5SDimitry Andric 83*5ffd83dbSDimitry Andric private: 84*5ffd83dbSDimitry Andric typedef void (PthreadLockChecker::*FnCheck)(const CallEvent &Call, 85*5ffd83dbSDimitry Andric CheckerContext &C, 86*5ffd83dbSDimitry Andric CheckerKind checkkind) const; 87*5ffd83dbSDimitry Andric CallDescriptionMap<FnCheck> PThreadCallbacks = { 88*5ffd83dbSDimitry Andric // Init. 89*5ffd83dbSDimitry Andric {{"pthread_mutex_init", 2}, &PthreadLockChecker::InitAnyLock}, 90*5ffd83dbSDimitry Andric // TODO: pthread_rwlock_init(2 arguments). 91*5ffd83dbSDimitry Andric // TODO: lck_mtx_init(3 arguments). 92*5ffd83dbSDimitry Andric // TODO: lck_mtx_alloc_init(2 arguments) => returns the mutex. 93*5ffd83dbSDimitry Andric // TODO: lck_rw_init(3 arguments). 94*5ffd83dbSDimitry Andric // TODO: lck_rw_alloc_init(2 arguments) => returns the mutex. 950b57cec5SDimitry Andric 96*5ffd83dbSDimitry Andric // Acquire. 97*5ffd83dbSDimitry Andric {{"pthread_mutex_lock", 1}, &PthreadLockChecker::AcquirePthreadLock}, 98*5ffd83dbSDimitry Andric {{"pthread_rwlock_rdlock", 1}, &PthreadLockChecker::AcquirePthreadLock}, 99*5ffd83dbSDimitry Andric {{"pthread_rwlock_wrlock", 1}, &PthreadLockChecker::AcquirePthreadLock}, 100*5ffd83dbSDimitry Andric {{"lck_mtx_lock", 1}, &PthreadLockChecker::AcquireXNULock}, 101*5ffd83dbSDimitry Andric {{"lck_rw_lock_exclusive", 1}, &PthreadLockChecker::AcquireXNULock}, 102*5ffd83dbSDimitry Andric {{"lck_rw_lock_shared", 1}, &PthreadLockChecker::AcquireXNULock}, 103*5ffd83dbSDimitry Andric 104*5ffd83dbSDimitry Andric // Try. 105*5ffd83dbSDimitry Andric {{"pthread_mutex_trylock", 1}, &PthreadLockChecker::TryPthreadLock}, 106*5ffd83dbSDimitry Andric {{"pthread_rwlock_tryrdlock", 1}, &PthreadLockChecker::TryPthreadLock}, 107*5ffd83dbSDimitry Andric {{"pthread_rwlock_trywrlock", 1}, &PthreadLockChecker::TryPthreadLock}, 108*5ffd83dbSDimitry Andric {{"lck_mtx_try_lock", 1}, &PthreadLockChecker::TryXNULock}, 109*5ffd83dbSDimitry Andric {{"lck_rw_try_lock_exclusive", 1}, &PthreadLockChecker::TryXNULock}, 110*5ffd83dbSDimitry Andric {{"lck_rw_try_lock_shared", 1}, &PthreadLockChecker::TryXNULock}, 111*5ffd83dbSDimitry Andric 112*5ffd83dbSDimitry Andric // Release. 113*5ffd83dbSDimitry Andric {{"pthread_mutex_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock}, 114*5ffd83dbSDimitry Andric {{"pthread_rwlock_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock}, 115*5ffd83dbSDimitry Andric {{"lck_mtx_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock}, 116*5ffd83dbSDimitry Andric {{"lck_rw_unlock_exclusive", 1}, &PthreadLockChecker::ReleaseAnyLock}, 117*5ffd83dbSDimitry Andric {{"lck_rw_unlock_shared", 1}, &PthreadLockChecker::ReleaseAnyLock}, 118*5ffd83dbSDimitry Andric {{"lck_rw_done", 1}, &PthreadLockChecker::ReleaseAnyLock}, 119*5ffd83dbSDimitry Andric 120*5ffd83dbSDimitry Andric // Destroy. 121*5ffd83dbSDimitry Andric {{"pthread_mutex_destroy", 1}, &PthreadLockChecker::DestroyPthreadLock}, 122*5ffd83dbSDimitry Andric {{"lck_mtx_destroy", 2}, &PthreadLockChecker::DestroyXNULock}, 123*5ffd83dbSDimitry Andric // TODO: pthread_rwlock_destroy(1 argument). 124*5ffd83dbSDimitry Andric // TODO: lck_rw_destroy(2 arguments). 125*5ffd83dbSDimitry Andric }; 126*5ffd83dbSDimitry Andric 127*5ffd83dbSDimitry Andric CallDescriptionMap<FnCheck> FuchsiaCallbacks = { 128*5ffd83dbSDimitry Andric // Init. 129*5ffd83dbSDimitry Andric {{"spin_lock_init", 1}, &PthreadLockChecker::InitAnyLock}, 130*5ffd83dbSDimitry Andric 131*5ffd83dbSDimitry Andric // Acquire. 132*5ffd83dbSDimitry Andric {{"spin_lock", 1}, &PthreadLockChecker::AcquirePthreadLock}, 133*5ffd83dbSDimitry Andric {{"spin_lock_save", 3}, &PthreadLockChecker::AcquirePthreadLock}, 134*5ffd83dbSDimitry Andric {{"sync_mutex_lock", 1}, &PthreadLockChecker::AcquirePthreadLock}, 135*5ffd83dbSDimitry Andric {{"sync_mutex_lock_with_waiter", 1}, 136*5ffd83dbSDimitry Andric &PthreadLockChecker::AcquirePthreadLock}, 137*5ffd83dbSDimitry Andric 138*5ffd83dbSDimitry Andric // Try. 139*5ffd83dbSDimitry Andric {{"spin_trylock", 1}, &PthreadLockChecker::TryFuchsiaLock}, 140*5ffd83dbSDimitry Andric {{"sync_mutex_trylock", 1}, &PthreadLockChecker::TryFuchsiaLock}, 141*5ffd83dbSDimitry Andric {{"sync_mutex_timedlock", 2}, &PthreadLockChecker::TryFuchsiaLock}, 142*5ffd83dbSDimitry Andric 143*5ffd83dbSDimitry Andric // Release. 144*5ffd83dbSDimitry Andric {{"spin_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock}, 145*5ffd83dbSDimitry Andric {{"spin_unlock_restore", 3}, &PthreadLockChecker::ReleaseAnyLock}, 146*5ffd83dbSDimitry Andric {{"sync_mutex_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock}, 147*5ffd83dbSDimitry Andric }; 148*5ffd83dbSDimitry Andric 149*5ffd83dbSDimitry Andric CallDescriptionMap<FnCheck> C11Callbacks = { 150*5ffd83dbSDimitry Andric // Init. 151*5ffd83dbSDimitry Andric {{"mtx_init", 2}, &PthreadLockChecker::InitAnyLock}, 152*5ffd83dbSDimitry Andric 153*5ffd83dbSDimitry Andric // Acquire. 154*5ffd83dbSDimitry Andric {{"mtx_lock", 1}, &PthreadLockChecker::AcquirePthreadLock}, 155*5ffd83dbSDimitry Andric 156*5ffd83dbSDimitry Andric // Try. 157*5ffd83dbSDimitry Andric {{"mtx_trylock", 1}, &PthreadLockChecker::TryC11Lock}, 158*5ffd83dbSDimitry Andric {{"mtx_timedlock", 2}, &PthreadLockChecker::TryC11Lock}, 159*5ffd83dbSDimitry Andric 160*5ffd83dbSDimitry Andric // Release. 161*5ffd83dbSDimitry Andric {{"mtx_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock}, 162*5ffd83dbSDimitry Andric 163*5ffd83dbSDimitry Andric // Destroy 164*5ffd83dbSDimitry Andric {{"mtx_destroy", 1}, &PthreadLockChecker::DestroyPthreadLock}, 165*5ffd83dbSDimitry Andric }; 166*5ffd83dbSDimitry Andric 1670b57cec5SDimitry Andric ProgramStateRef resolvePossiblyDestroyedMutex(ProgramStateRef state, 1680b57cec5SDimitry Andric const MemRegion *lockR, 1690b57cec5SDimitry Andric const SymbolRef *sym) const; 170*5ffd83dbSDimitry Andric void reportUseDestroyedBug(const CallEvent &Call, CheckerContext &C, 171*5ffd83dbSDimitry Andric unsigned ArgNo, CheckerKind checkKind) const; 172*5ffd83dbSDimitry Andric 173*5ffd83dbSDimitry Andric // Init. 174*5ffd83dbSDimitry Andric void InitAnyLock(const CallEvent &Call, CheckerContext &C, 175*5ffd83dbSDimitry Andric CheckerKind checkkind) const; 176*5ffd83dbSDimitry Andric void InitLockAux(const CallEvent &Call, CheckerContext &C, unsigned ArgNo, 177*5ffd83dbSDimitry Andric SVal Lock, CheckerKind checkkind) const; 178*5ffd83dbSDimitry Andric 179*5ffd83dbSDimitry Andric // Lock, Try-lock. 180*5ffd83dbSDimitry Andric void AcquirePthreadLock(const CallEvent &Call, CheckerContext &C, 181*5ffd83dbSDimitry Andric CheckerKind checkkind) const; 182*5ffd83dbSDimitry Andric void AcquireXNULock(const CallEvent &Call, CheckerContext &C, 183*5ffd83dbSDimitry Andric CheckerKind checkkind) const; 184*5ffd83dbSDimitry Andric void TryPthreadLock(const CallEvent &Call, CheckerContext &C, 185*5ffd83dbSDimitry Andric CheckerKind checkkind) const; 186*5ffd83dbSDimitry Andric void TryXNULock(const CallEvent &Call, CheckerContext &C, 187*5ffd83dbSDimitry Andric CheckerKind checkkind) const; 188*5ffd83dbSDimitry Andric void TryFuchsiaLock(const CallEvent &Call, CheckerContext &C, 189*5ffd83dbSDimitry Andric CheckerKind checkkind) const; 190*5ffd83dbSDimitry Andric void TryC11Lock(const CallEvent &Call, CheckerContext &C, 191*5ffd83dbSDimitry Andric CheckerKind checkkind) const; 192*5ffd83dbSDimitry Andric void AcquireLockAux(const CallEvent &Call, CheckerContext &C, unsigned ArgNo, 193*5ffd83dbSDimitry Andric SVal lock, bool isTryLock, LockingSemantics semantics, 194*5ffd83dbSDimitry Andric CheckerKind checkkind) const; 195*5ffd83dbSDimitry Andric 196*5ffd83dbSDimitry Andric // Release. 197*5ffd83dbSDimitry Andric void ReleaseAnyLock(const CallEvent &Call, CheckerContext &C, 198*5ffd83dbSDimitry Andric CheckerKind checkkind) const; 199*5ffd83dbSDimitry Andric void ReleaseLockAux(const CallEvent &Call, CheckerContext &C, unsigned ArgNo, 200*5ffd83dbSDimitry Andric SVal lock, CheckerKind checkkind) const; 201*5ffd83dbSDimitry Andric 202*5ffd83dbSDimitry Andric // Destroy. 203*5ffd83dbSDimitry Andric void DestroyPthreadLock(const CallEvent &Call, CheckerContext &C, 204*5ffd83dbSDimitry Andric CheckerKind checkkind) const; 205*5ffd83dbSDimitry Andric void DestroyXNULock(const CallEvent &Call, CheckerContext &C, 206*5ffd83dbSDimitry Andric CheckerKind checkkind) const; 207*5ffd83dbSDimitry Andric void DestroyLockAux(const CallEvent &Call, CheckerContext &C, unsigned ArgNo, 208*5ffd83dbSDimitry Andric SVal Lock, LockingSemantics semantics, 209*5ffd83dbSDimitry Andric CheckerKind checkkind) const; 210*5ffd83dbSDimitry Andric 211*5ffd83dbSDimitry Andric public: 212*5ffd83dbSDimitry Andric void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 213*5ffd83dbSDimitry Andric void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; 214*5ffd83dbSDimitry Andric ProgramStateRef 215*5ffd83dbSDimitry Andric checkRegionChanges(ProgramStateRef State, const InvalidatedSymbols *Symbols, 216*5ffd83dbSDimitry Andric ArrayRef<const MemRegion *> ExplicitRegions, 217*5ffd83dbSDimitry Andric ArrayRef<const MemRegion *> Regions, 218*5ffd83dbSDimitry Andric const LocationContext *LCtx, const CallEvent *Call) const; 219*5ffd83dbSDimitry Andric void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, 220*5ffd83dbSDimitry Andric const char *Sep) const override; 221*5ffd83dbSDimitry Andric 222*5ffd83dbSDimitry Andric private: 223*5ffd83dbSDimitry Andric mutable std::unique_ptr<BugType> BT_doublelock[CK_NumCheckKinds]; 224*5ffd83dbSDimitry Andric mutable std::unique_ptr<BugType> BT_doubleunlock[CK_NumCheckKinds]; 225*5ffd83dbSDimitry Andric mutable std::unique_ptr<BugType> BT_destroylock[CK_NumCheckKinds]; 226*5ffd83dbSDimitry Andric mutable std::unique_ptr<BugType> BT_initlock[CK_NumCheckKinds]; 227*5ffd83dbSDimitry Andric mutable std::unique_ptr<BugType> BT_lor[CK_NumCheckKinds]; 228*5ffd83dbSDimitry Andric 229*5ffd83dbSDimitry Andric void initBugType(CheckerKind checkKind) const { 230*5ffd83dbSDimitry Andric if (BT_doublelock[checkKind]) 231*5ffd83dbSDimitry Andric return; 232*5ffd83dbSDimitry Andric BT_doublelock[checkKind].reset( 233*5ffd83dbSDimitry Andric new BugType{CheckNames[checkKind], "Double locking", "Lock checker"}); 234*5ffd83dbSDimitry Andric BT_doubleunlock[checkKind].reset( 235*5ffd83dbSDimitry Andric new BugType{CheckNames[checkKind], "Double unlocking", "Lock checker"}); 236*5ffd83dbSDimitry Andric BT_destroylock[checkKind].reset(new BugType{ 237*5ffd83dbSDimitry Andric CheckNames[checkKind], "Use destroyed lock", "Lock checker"}); 238*5ffd83dbSDimitry Andric BT_initlock[checkKind].reset(new BugType{ 239*5ffd83dbSDimitry Andric CheckNames[checkKind], "Init invalid lock", "Lock checker"}); 240*5ffd83dbSDimitry Andric BT_lor[checkKind].reset(new BugType{CheckNames[checkKind], 241*5ffd83dbSDimitry Andric "Lock order reversal", "Lock checker"}); 242*5ffd83dbSDimitry Andric } 2430b57cec5SDimitry Andric }; 2440b57cec5SDimitry Andric } // end anonymous namespace 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric // A stack of locks for tracking lock-unlock order. 2470b57cec5SDimitry Andric REGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *) 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric // An entry for tracking lock states. 2500b57cec5SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(LockMap, const MemRegion *, LockState) 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric // Return values for unresolved calls to pthread_mutex_destroy(). 2530b57cec5SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(DestroyRetVal, const MemRegion *, SymbolRef) 2540b57cec5SDimitry Andric 255*5ffd83dbSDimitry Andric void PthreadLockChecker::checkPostCall(const CallEvent &Call, 2560b57cec5SDimitry Andric CheckerContext &C) const { 257*5ffd83dbSDimitry Andric // An additional umbrella check that all functions modeled by this checker 258*5ffd83dbSDimitry Andric // are global C functions. 259*5ffd83dbSDimitry Andric // TODO: Maybe make this the default behavior of CallDescription 260*5ffd83dbSDimitry Andric // with exactly one identifier? 261*5ffd83dbSDimitry Andric // FIXME: Try to handle cases when the implementation was inlined rather 262*5ffd83dbSDimitry Andric // than just giving up. 263*5ffd83dbSDimitry Andric if (!Call.isGlobalCFunction() || C.wasInlined) 2640b57cec5SDimitry Andric return; 2650b57cec5SDimitry Andric 266*5ffd83dbSDimitry Andric if (const FnCheck *Callback = PThreadCallbacks.lookup(Call)) 267*5ffd83dbSDimitry Andric (this->**Callback)(Call, C, CK_PthreadLockChecker); 268*5ffd83dbSDimitry Andric else if (const FnCheck *Callback = FuchsiaCallbacks.lookup(Call)) 269*5ffd83dbSDimitry Andric (this->**Callback)(Call, C, CK_FuchsiaLockChecker); 270*5ffd83dbSDimitry Andric else if (const FnCheck *Callback = C11Callbacks.lookup(Call)) 271*5ffd83dbSDimitry Andric (this->**Callback)(Call, C, CK_C11LockChecker); 2720b57cec5SDimitry Andric } 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric // When a lock is destroyed, in some semantics(like PthreadSemantics) we are not 2750b57cec5SDimitry Andric // sure if the destroy call has succeeded or failed, and the lock enters one of 2760b57cec5SDimitry Andric // the 'possibly destroyed' state. There is a short time frame for the 2770b57cec5SDimitry Andric // programmer to check the return value to see if the lock was successfully 2780b57cec5SDimitry Andric // destroyed. Before we model the next operation over that lock, we call this 2790b57cec5SDimitry Andric // function to see if the return value was checked by now and set the lock state 2800b57cec5SDimitry Andric // - either to destroyed state or back to its previous state. 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric // In PthreadSemantics, pthread_mutex_destroy() returns zero if the lock is 2830b57cec5SDimitry Andric // successfully destroyed and it returns a non-zero value otherwise. 2840b57cec5SDimitry Andric ProgramStateRef PthreadLockChecker::resolvePossiblyDestroyedMutex( 2850b57cec5SDimitry Andric ProgramStateRef state, const MemRegion *lockR, const SymbolRef *sym) const { 2860b57cec5SDimitry Andric const LockState *lstate = state->get<LockMap>(lockR); 2870b57cec5SDimitry Andric // Existence in DestroyRetVal ensures existence in LockMap. 2880b57cec5SDimitry Andric // Existence in Destroyed also ensures that the lock state for lockR is either 2890b57cec5SDimitry Andric // UntouchedAndPossiblyDestroyed or UnlockedAndPossiblyDestroyed. 2900b57cec5SDimitry Andric assert(lstate->isUntouchedAndPossiblyDestroyed() || 2910b57cec5SDimitry Andric lstate->isUnlockedAndPossiblyDestroyed()); 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric ConstraintManager &CMgr = state->getConstraintManager(); 2940b57cec5SDimitry Andric ConditionTruthVal retZero = CMgr.isNull(state, *sym); 2950b57cec5SDimitry Andric if (retZero.isConstrainedFalse()) { 2960b57cec5SDimitry Andric if (lstate->isUntouchedAndPossiblyDestroyed()) 2970b57cec5SDimitry Andric state = state->remove<LockMap>(lockR); 2980b57cec5SDimitry Andric else if (lstate->isUnlockedAndPossiblyDestroyed()) 2990b57cec5SDimitry Andric state = state->set<LockMap>(lockR, LockState::getUnlocked()); 3000b57cec5SDimitry Andric } else 3010b57cec5SDimitry Andric state = state->set<LockMap>(lockR, LockState::getDestroyed()); 3020b57cec5SDimitry Andric 3030b57cec5SDimitry Andric // Removing the map entry (lockR, sym) from DestroyRetVal as the lock state is 3040b57cec5SDimitry Andric // now resolved. 3050b57cec5SDimitry Andric state = state->remove<DestroyRetVal>(lockR); 3060b57cec5SDimitry Andric return state; 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric void PthreadLockChecker::printState(raw_ostream &Out, ProgramStateRef State, 3100b57cec5SDimitry Andric const char *NL, const char *Sep) const { 3110b57cec5SDimitry Andric LockMapTy LM = State->get<LockMap>(); 3120b57cec5SDimitry Andric if (!LM.isEmpty()) { 3130b57cec5SDimitry Andric Out << Sep << "Mutex states:" << NL; 3140b57cec5SDimitry Andric for (auto I : LM) { 3150b57cec5SDimitry Andric I.first->dumpToStream(Out); 3160b57cec5SDimitry Andric if (I.second.isLocked()) 3170b57cec5SDimitry Andric Out << ": locked"; 3180b57cec5SDimitry Andric else if (I.second.isUnlocked()) 3190b57cec5SDimitry Andric Out << ": unlocked"; 3200b57cec5SDimitry Andric else if (I.second.isDestroyed()) 3210b57cec5SDimitry Andric Out << ": destroyed"; 3220b57cec5SDimitry Andric else if (I.second.isUntouchedAndPossiblyDestroyed()) 3230b57cec5SDimitry Andric Out << ": not tracked, possibly destroyed"; 3240b57cec5SDimitry Andric else if (I.second.isUnlockedAndPossiblyDestroyed()) 3250b57cec5SDimitry Andric Out << ": unlocked, possibly destroyed"; 3260b57cec5SDimitry Andric Out << NL; 3270b57cec5SDimitry Andric } 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric 3300b57cec5SDimitry Andric LockSetTy LS = State->get<LockSet>(); 3310b57cec5SDimitry Andric if (!LS.isEmpty()) { 3320b57cec5SDimitry Andric Out << Sep << "Mutex lock order:" << NL; 3330b57cec5SDimitry Andric for (auto I : LS) { 3340b57cec5SDimitry Andric I->dumpToStream(Out); 3350b57cec5SDimitry Andric Out << NL; 3360b57cec5SDimitry Andric } 3370b57cec5SDimitry Andric } 3380b57cec5SDimitry Andric 3390b57cec5SDimitry Andric // TODO: Dump destroyed mutex symbols? 3400b57cec5SDimitry Andric } 3410b57cec5SDimitry Andric 342*5ffd83dbSDimitry Andric void PthreadLockChecker::AcquirePthreadLock(const CallEvent &Call, 343*5ffd83dbSDimitry Andric CheckerContext &C, 344*5ffd83dbSDimitry Andric CheckerKind checkKind) const { 345*5ffd83dbSDimitry Andric AcquireLockAux(Call, C, 0, Call.getArgSVal(0), false, PthreadSemantics, 346*5ffd83dbSDimitry Andric checkKind); 347*5ffd83dbSDimitry Andric } 348*5ffd83dbSDimitry Andric 349*5ffd83dbSDimitry Andric void PthreadLockChecker::AcquireXNULock(const CallEvent &Call, 350*5ffd83dbSDimitry Andric CheckerContext &C, 351*5ffd83dbSDimitry Andric CheckerKind checkKind) const { 352*5ffd83dbSDimitry Andric AcquireLockAux(Call, C, 0, Call.getArgSVal(0), false, XNUSemantics, 353*5ffd83dbSDimitry Andric checkKind); 354*5ffd83dbSDimitry Andric } 355*5ffd83dbSDimitry Andric 356*5ffd83dbSDimitry Andric void PthreadLockChecker::TryPthreadLock(const CallEvent &Call, 357*5ffd83dbSDimitry Andric CheckerContext &C, 358*5ffd83dbSDimitry Andric CheckerKind checkKind) const { 359*5ffd83dbSDimitry Andric AcquireLockAux(Call, C, 0, Call.getArgSVal(0), true, PthreadSemantics, 360*5ffd83dbSDimitry Andric checkKind); 361*5ffd83dbSDimitry Andric } 362*5ffd83dbSDimitry Andric 363*5ffd83dbSDimitry Andric void PthreadLockChecker::TryXNULock(const CallEvent &Call, CheckerContext &C, 364*5ffd83dbSDimitry Andric CheckerKind checkKind) const { 365*5ffd83dbSDimitry Andric AcquireLockAux(Call, C, 0, Call.getArgSVal(0), true, PthreadSemantics, 366*5ffd83dbSDimitry Andric checkKind); 367*5ffd83dbSDimitry Andric } 368*5ffd83dbSDimitry Andric 369*5ffd83dbSDimitry Andric void PthreadLockChecker::TryFuchsiaLock(const CallEvent &Call, 370*5ffd83dbSDimitry Andric CheckerContext &C, 371*5ffd83dbSDimitry Andric CheckerKind checkKind) const { 372*5ffd83dbSDimitry Andric AcquireLockAux(Call, C, 0, Call.getArgSVal(0), true, PthreadSemantics, 373*5ffd83dbSDimitry Andric checkKind); 374*5ffd83dbSDimitry Andric } 375*5ffd83dbSDimitry Andric 376*5ffd83dbSDimitry Andric void PthreadLockChecker::TryC11Lock(const CallEvent &Call, CheckerContext &C, 377*5ffd83dbSDimitry Andric CheckerKind checkKind) const { 378*5ffd83dbSDimitry Andric AcquireLockAux(Call, C, 0, Call.getArgSVal(0), true, PthreadSemantics, 379*5ffd83dbSDimitry Andric checkKind); 380*5ffd83dbSDimitry Andric } 381*5ffd83dbSDimitry Andric 382*5ffd83dbSDimitry Andric void PthreadLockChecker::AcquireLockAux(const CallEvent &Call, 383*5ffd83dbSDimitry Andric CheckerContext &C, unsigned ArgNo, 3840b57cec5SDimitry Andric SVal lock, bool isTryLock, 385*5ffd83dbSDimitry Andric enum LockingSemantics semantics, 386*5ffd83dbSDimitry Andric CheckerKind checkKind) const { 387*5ffd83dbSDimitry Andric if (!ChecksEnabled[checkKind]) 388*5ffd83dbSDimitry Andric return; 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric const MemRegion *lockR = lock.getAsRegion(); 3910b57cec5SDimitry Andric if (!lockR) 3920b57cec5SDimitry Andric return; 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 3950b57cec5SDimitry Andric const SymbolRef *sym = state->get<DestroyRetVal>(lockR); 3960b57cec5SDimitry Andric if (sym) 3970b57cec5SDimitry Andric state = resolvePossiblyDestroyedMutex(state, lockR, sym); 3980b57cec5SDimitry Andric 3990b57cec5SDimitry Andric if (const LockState *LState = state->get<LockMap>(lockR)) { 4000b57cec5SDimitry Andric if (LState->isLocked()) { 4010b57cec5SDimitry Andric ExplodedNode *N = C.generateErrorNode(); 4020b57cec5SDimitry Andric if (!N) 4030b57cec5SDimitry Andric return; 404*5ffd83dbSDimitry Andric initBugType(checkKind); 405a7dea167SDimitry Andric auto report = std::make_unique<PathSensitiveBugReport>( 406*5ffd83dbSDimitry Andric *BT_doublelock[checkKind], "This lock has already been acquired", N); 407*5ffd83dbSDimitry Andric report->addRange(Call.getArgExpr(ArgNo)->getSourceRange()); 4080b57cec5SDimitry Andric C.emitReport(std::move(report)); 4090b57cec5SDimitry Andric return; 4100b57cec5SDimitry Andric } else if (LState->isDestroyed()) { 411*5ffd83dbSDimitry Andric reportUseDestroyedBug(Call, C, ArgNo, checkKind); 4120b57cec5SDimitry Andric return; 4130b57cec5SDimitry Andric } 4140b57cec5SDimitry Andric } 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric ProgramStateRef lockSucc = state; 4170b57cec5SDimitry Andric if (isTryLock) { 4180b57cec5SDimitry Andric // Bifurcate the state, and allow a mode where the lock acquisition fails. 419*5ffd83dbSDimitry Andric SVal RetVal = Call.getReturnValue(); 420*5ffd83dbSDimitry Andric if (auto DefinedRetVal = RetVal.getAs<DefinedSVal>()) { 4210b57cec5SDimitry Andric ProgramStateRef lockFail; 4220b57cec5SDimitry Andric switch (semantics) { 4230b57cec5SDimitry Andric case PthreadSemantics: 424*5ffd83dbSDimitry Andric std::tie(lockFail, lockSucc) = state->assume(*DefinedRetVal); 4250b57cec5SDimitry Andric break; 4260b57cec5SDimitry Andric case XNUSemantics: 427*5ffd83dbSDimitry Andric std::tie(lockSucc, lockFail) = state->assume(*DefinedRetVal); 4280b57cec5SDimitry Andric break; 4290b57cec5SDimitry Andric default: 4300b57cec5SDimitry Andric llvm_unreachable("Unknown tryLock locking semantics"); 4310b57cec5SDimitry Andric } 4320b57cec5SDimitry Andric assert(lockFail && lockSucc); 4330b57cec5SDimitry Andric C.addTransition(lockFail); 434*5ffd83dbSDimitry Andric } 435*5ffd83dbSDimitry Andric // We might want to handle the case when the mutex lock function was inlined 436*5ffd83dbSDimitry Andric // and returned an Unknown or Undefined value. 4370b57cec5SDimitry Andric } else if (semantics == PthreadSemantics) { 4380b57cec5SDimitry Andric // Assume that the return value was 0. 439*5ffd83dbSDimitry Andric SVal RetVal = Call.getReturnValue(); 440*5ffd83dbSDimitry Andric if (auto DefinedRetVal = RetVal.getAs<DefinedSVal>()) { 441*5ffd83dbSDimitry Andric // FIXME: If the lock function was inlined and returned true, 442*5ffd83dbSDimitry Andric // we need to behave sanely - at least generate sink. 443*5ffd83dbSDimitry Andric lockSucc = state->assume(*DefinedRetVal, false); 4440b57cec5SDimitry Andric assert(lockSucc); 445*5ffd83dbSDimitry Andric } 446*5ffd83dbSDimitry Andric // We might want to handle the case when the mutex lock function was inlined 447*5ffd83dbSDimitry Andric // and returned an Unknown or Undefined value. 4480b57cec5SDimitry Andric } else { 4490b57cec5SDimitry Andric // XNU locking semantics return void on non-try locks 4500b57cec5SDimitry Andric assert((semantics == XNUSemantics) && "Unknown locking semantics"); 4510b57cec5SDimitry Andric lockSucc = state; 4520b57cec5SDimitry Andric } 4530b57cec5SDimitry Andric 4540b57cec5SDimitry Andric // Record that the lock was acquired. 4550b57cec5SDimitry Andric lockSucc = lockSucc->add<LockSet>(lockR); 4560b57cec5SDimitry Andric lockSucc = lockSucc->set<LockMap>(lockR, LockState::getLocked()); 4570b57cec5SDimitry Andric C.addTransition(lockSucc); 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric 460*5ffd83dbSDimitry Andric void PthreadLockChecker::ReleaseAnyLock(const CallEvent &Call, 461*5ffd83dbSDimitry Andric CheckerContext &C, 462*5ffd83dbSDimitry Andric CheckerKind checkKind) const { 463*5ffd83dbSDimitry Andric ReleaseLockAux(Call, C, 0, Call.getArgSVal(0), checkKind); 464*5ffd83dbSDimitry Andric } 465*5ffd83dbSDimitry Andric 466*5ffd83dbSDimitry Andric void PthreadLockChecker::ReleaseLockAux(const CallEvent &Call, 467*5ffd83dbSDimitry Andric CheckerContext &C, unsigned ArgNo, 468*5ffd83dbSDimitry Andric SVal lock, 469*5ffd83dbSDimitry Andric CheckerKind checkKind) const { 470*5ffd83dbSDimitry Andric if (!ChecksEnabled[checkKind]) 471*5ffd83dbSDimitry Andric return; 4720b57cec5SDimitry Andric 4730b57cec5SDimitry Andric const MemRegion *lockR = lock.getAsRegion(); 4740b57cec5SDimitry Andric if (!lockR) 4750b57cec5SDimitry Andric return; 4760b57cec5SDimitry Andric 4770b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 4780b57cec5SDimitry Andric const SymbolRef *sym = state->get<DestroyRetVal>(lockR); 4790b57cec5SDimitry Andric if (sym) 4800b57cec5SDimitry Andric state = resolvePossiblyDestroyedMutex(state, lockR, sym); 4810b57cec5SDimitry Andric 4820b57cec5SDimitry Andric if (const LockState *LState = state->get<LockMap>(lockR)) { 4830b57cec5SDimitry Andric if (LState->isUnlocked()) { 4840b57cec5SDimitry Andric ExplodedNode *N = C.generateErrorNode(); 4850b57cec5SDimitry Andric if (!N) 4860b57cec5SDimitry Andric return; 487*5ffd83dbSDimitry Andric initBugType(checkKind); 488a7dea167SDimitry Andric auto Report = std::make_unique<PathSensitiveBugReport>( 489*5ffd83dbSDimitry Andric *BT_doubleunlock[checkKind], "This lock has already been unlocked", 490*5ffd83dbSDimitry Andric N); 491*5ffd83dbSDimitry Andric Report->addRange(Call.getArgExpr(ArgNo)->getSourceRange()); 4920b57cec5SDimitry Andric C.emitReport(std::move(Report)); 4930b57cec5SDimitry Andric return; 4940b57cec5SDimitry Andric } else if (LState->isDestroyed()) { 495*5ffd83dbSDimitry Andric reportUseDestroyedBug(Call, C, ArgNo, checkKind); 4960b57cec5SDimitry Andric return; 4970b57cec5SDimitry Andric } 4980b57cec5SDimitry Andric } 4990b57cec5SDimitry Andric 5000b57cec5SDimitry Andric LockSetTy LS = state->get<LockSet>(); 5010b57cec5SDimitry Andric 5020b57cec5SDimitry Andric if (!LS.isEmpty()) { 5030b57cec5SDimitry Andric const MemRegion *firstLockR = LS.getHead(); 5040b57cec5SDimitry Andric if (firstLockR != lockR) { 5050b57cec5SDimitry Andric ExplodedNode *N = C.generateErrorNode(); 5060b57cec5SDimitry Andric if (!N) 5070b57cec5SDimitry Andric return; 508*5ffd83dbSDimitry Andric initBugType(checkKind); 509a7dea167SDimitry Andric auto report = std::make_unique<PathSensitiveBugReport>( 510*5ffd83dbSDimitry Andric *BT_lor[checkKind], 511*5ffd83dbSDimitry Andric "This was not the most recently acquired lock. Possible " 512*5ffd83dbSDimitry Andric "lock order reversal", 513*5ffd83dbSDimitry Andric N); 514*5ffd83dbSDimitry Andric report->addRange(Call.getArgExpr(ArgNo)->getSourceRange()); 5150b57cec5SDimitry Andric C.emitReport(std::move(report)); 5160b57cec5SDimitry Andric return; 5170b57cec5SDimitry Andric } 5180b57cec5SDimitry Andric // Record that the lock was released. 5190b57cec5SDimitry Andric state = state->set<LockSet>(LS.getTail()); 5200b57cec5SDimitry Andric } 5210b57cec5SDimitry Andric 5220b57cec5SDimitry Andric state = state->set<LockMap>(lockR, LockState::getUnlocked()); 5230b57cec5SDimitry Andric C.addTransition(state); 5240b57cec5SDimitry Andric } 5250b57cec5SDimitry Andric 526*5ffd83dbSDimitry Andric void PthreadLockChecker::DestroyPthreadLock(const CallEvent &Call, 527*5ffd83dbSDimitry Andric CheckerContext &C, 528*5ffd83dbSDimitry Andric CheckerKind checkKind) const { 529*5ffd83dbSDimitry Andric DestroyLockAux(Call, C, 0, Call.getArgSVal(0), PthreadSemantics, checkKind); 530*5ffd83dbSDimitry Andric } 531*5ffd83dbSDimitry Andric 532*5ffd83dbSDimitry Andric void PthreadLockChecker::DestroyXNULock(const CallEvent &Call, 533*5ffd83dbSDimitry Andric CheckerContext &C, 534*5ffd83dbSDimitry Andric CheckerKind checkKind) const { 535*5ffd83dbSDimitry Andric DestroyLockAux(Call, C, 0, Call.getArgSVal(0), XNUSemantics, checkKind); 536*5ffd83dbSDimitry Andric } 537*5ffd83dbSDimitry Andric 538*5ffd83dbSDimitry Andric void PthreadLockChecker::DestroyLockAux(const CallEvent &Call, 539*5ffd83dbSDimitry Andric CheckerContext &C, unsigned ArgNo, 5400b57cec5SDimitry Andric SVal Lock, 541*5ffd83dbSDimitry Andric enum LockingSemantics semantics, 542*5ffd83dbSDimitry Andric CheckerKind checkKind) const { 543*5ffd83dbSDimitry Andric if (!ChecksEnabled[checkKind]) 544*5ffd83dbSDimitry Andric return; 5450b57cec5SDimitry Andric 5460b57cec5SDimitry Andric const MemRegion *LockR = Lock.getAsRegion(); 5470b57cec5SDimitry Andric if (!LockR) 5480b57cec5SDimitry Andric return; 5490b57cec5SDimitry Andric 5500b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 5510b57cec5SDimitry Andric 5520b57cec5SDimitry Andric const SymbolRef *sym = State->get<DestroyRetVal>(LockR); 5530b57cec5SDimitry Andric if (sym) 5540b57cec5SDimitry Andric State = resolvePossiblyDestroyedMutex(State, LockR, sym); 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric const LockState *LState = State->get<LockMap>(LockR); 5570b57cec5SDimitry Andric // Checking the return value of the destroy method only in the case of 5580b57cec5SDimitry Andric // PthreadSemantics 5590b57cec5SDimitry Andric if (semantics == PthreadSemantics) { 5600b57cec5SDimitry Andric if (!LState || LState->isUnlocked()) { 561*5ffd83dbSDimitry Andric SymbolRef sym = Call.getReturnValue().getAsSymbol(); 5620b57cec5SDimitry Andric if (!sym) { 5630b57cec5SDimitry Andric State = State->remove<LockMap>(LockR); 5640b57cec5SDimitry Andric C.addTransition(State); 5650b57cec5SDimitry Andric return; 5660b57cec5SDimitry Andric } 5670b57cec5SDimitry Andric State = State->set<DestroyRetVal>(LockR, sym); 5680b57cec5SDimitry Andric if (LState && LState->isUnlocked()) 5690b57cec5SDimitry Andric State = State->set<LockMap>( 5700b57cec5SDimitry Andric LockR, LockState::getUnlockedAndPossiblyDestroyed()); 5710b57cec5SDimitry Andric else 5720b57cec5SDimitry Andric State = State->set<LockMap>( 5730b57cec5SDimitry Andric LockR, LockState::getUntouchedAndPossiblyDestroyed()); 5740b57cec5SDimitry Andric C.addTransition(State); 5750b57cec5SDimitry Andric return; 5760b57cec5SDimitry Andric } 5770b57cec5SDimitry Andric } else { 5780b57cec5SDimitry Andric if (!LState || LState->isUnlocked()) { 5790b57cec5SDimitry Andric State = State->set<LockMap>(LockR, LockState::getDestroyed()); 5800b57cec5SDimitry Andric C.addTransition(State); 5810b57cec5SDimitry Andric return; 5820b57cec5SDimitry Andric } 5830b57cec5SDimitry Andric } 5840b57cec5SDimitry Andric StringRef Message; 5850b57cec5SDimitry Andric 5860b57cec5SDimitry Andric if (LState->isLocked()) { 5870b57cec5SDimitry Andric Message = "This lock is still locked"; 5880b57cec5SDimitry Andric } else { 5890b57cec5SDimitry Andric Message = "This lock has already been destroyed"; 5900b57cec5SDimitry Andric } 5910b57cec5SDimitry Andric 5920b57cec5SDimitry Andric ExplodedNode *N = C.generateErrorNode(); 5930b57cec5SDimitry Andric if (!N) 5940b57cec5SDimitry Andric return; 595*5ffd83dbSDimitry Andric initBugType(checkKind); 596*5ffd83dbSDimitry Andric auto Report = std::make_unique<PathSensitiveBugReport>( 597*5ffd83dbSDimitry Andric *BT_destroylock[checkKind], Message, N); 598*5ffd83dbSDimitry Andric Report->addRange(Call.getArgExpr(ArgNo)->getSourceRange()); 5990b57cec5SDimitry Andric C.emitReport(std::move(Report)); 6000b57cec5SDimitry Andric } 6010b57cec5SDimitry Andric 602*5ffd83dbSDimitry Andric void PthreadLockChecker::InitAnyLock(const CallEvent &Call, CheckerContext &C, 603*5ffd83dbSDimitry Andric CheckerKind checkKind) const { 604*5ffd83dbSDimitry Andric InitLockAux(Call, C, 0, Call.getArgSVal(0), checkKind); 605*5ffd83dbSDimitry Andric } 606*5ffd83dbSDimitry Andric 607*5ffd83dbSDimitry Andric void PthreadLockChecker::InitLockAux(const CallEvent &Call, CheckerContext &C, 608*5ffd83dbSDimitry Andric unsigned ArgNo, SVal Lock, 609*5ffd83dbSDimitry Andric CheckerKind checkKind) const { 610*5ffd83dbSDimitry Andric if (!ChecksEnabled[checkKind]) 611*5ffd83dbSDimitry Andric return; 6120b57cec5SDimitry Andric 6130b57cec5SDimitry Andric const MemRegion *LockR = Lock.getAsRegion(); 6140b57cec5SDimitry Andric if (!LockR) 6150b57cec5SDimitry Andric return; 6160b57cec5SDimitry Andric 6170b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 6180b57cec5SDimitry Andric 6190b57cec5SDimitry Andric const SymbolRef *sym = State->get<DestroyRetVal>(LockR); 6200b57cec5SDimitry Andric if (sym) 6210b57cec5SDimitry Andric State = resolvePossiblyDestroyedMutex(State, LockR, sym); 6220b57cec5SDimitry Andric 6230b57cec5SDimitry Andric const struct LockState *LState = State->get<LockMap>(LockR); 6240b57cec5SDimitry Andric if (!LState || LState->isDestroyed()) { 6250b57cec5SDimitry Andric State = State->set<LockMap>(LockR, LockState::getUnlocked()); 6260b57cec5SDimitry Andric C.addTransition(State); 6270b57cec5SDimitry Andric return; 6280b57cec5SDimitry Andric } 6290b57cec5SDimitry Andric 6300b57cec5SDimitry Andric StringRef Message; 6310b57cec5SDimitry Andric 6320b57cec5SDimitry Andric if (LState->isLocked()) { 6330b57cec5SDimitry Andric Message = "This lock is still being held"; 6340b57cec5SDimitry Andric } else { 6350b57cec5SDimitry Andric Message = "This lock has already been initialized"; 6360b57cec5SDimitry Andric } 6370b57cec5SDimitry Andric 6380b57cec5SDimitry Andric ExplodedNode *N = C.generateErrorNode(); 6390b57cec5SDimitry Andric if (!N) 6400b57cec5SDimitry Andric return; 641*5ffd83dbSDimitry Andric initBugType(checkKind); 642*5ffd83dbSDimitry Andric auto Report = std::make_unique<PathSensitiveBugReport>( 643*5ffd83dbSDimitry Andric *BT_initlock[checkKind], Message, N); 644*5ffd83dbSDimitry Andric Report->addRange(Call.getArgExpr(ArgNo)->getSourceRange()); 6450b57cec5SDimitry Andric C.emitReport(std::move(Report)); 6460b57cec5SDimitry Andric } 6470b57cec5SDimitry Andric 648*5ffd83dbSDimitry Andric void PthreadLockChecker::reportUseDestroyedBug(const CallEvent &Call, 649*5ffd83dbSDimitry Andric CheckerContext &C, 650*5ffd83dbSDimitry Andric unsigned ArgNo, 651*5ffd83dbSDimitry Andric CheckerKind checkKind) const { 6520b57cec5SDimitry Andric ExplodedNode *N = C.generateErrorNode(); 6530b57cec5SDimitry Andric if (!N) 6540b57cec5SDimitry Andric return; 655*5ffd83dbSDimitry Andric initBugType(checkKind); 656a7dea167SDimitry Andric auto Report = std::make_unique<PathSensitiveBugReport>( 657*5ffd83dbSDimitry Andric *BT_destroylock[checkKind], "This lock has already been destroyed", N); 658*5ffd83dbSDimitry Andric Report->addRange(Call.getArgExpr(ArgNo)->getSourceRange()); 6590b57cec5SDimitry Andric C.emitReport(std::move(Report)); 6600b57cec5SDimitry Andric } 6610b57cec5SDimitry Andric 6620b57cec5SDimitry Andric void PthreadLockChecker::checkDeadSymbols(SymbolReaper &SymReaper, 6630b57cec5SDimitry Andric CheckerContext &C) const { 6640b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 6650b57cec5SDimitry Andric 666*5ffd83dbSDimitry Andric for (auto I : State->get<DestroyRetVal>()) { 667*5ffd83dbSDimitry Andric // Once the return value symbol dies, no more checks can be performed 668*5ffd83dbSDimitry Andric // against it. See if the return value was checked before this point. 669*5ffd83dbSDimitry Andric // This would remove the symbol from the map as well. 670*5ffd83dbSDimitry Andric if (SymReaper.isDead(I.second)) 671*5ffd83dbSDimitry Andric State = resolvePossiblyDestroyedMutex(State, I.first, &I.second); 6720b57cec5SDimitry Andric } 673*5ffd83dbSDimitry Andric 674*5ffd83dbSDimitry Andric for (auto I : State->get<LockMap>()) { 675*5ffd83dbSDimitry Andric // Stop tracking dead mutex regions as well. 676*5ffd83dbSDimitry Andric if (!SymReaper.isLiveRegion(I.first)) 677*5ffd83dbSDimitry Andric State = State->remove<LockMap>(I.first); 678*5ffd83dbSDimitry Andric } 679*5ffd83dbSDimitry Andric 680*5ffd83dbSDimitry Andric // TODO: We probably need to clean up the lock stack as well. 681*5ffd83dbSDimitry Andric // It is tricky though: even if the mutex cannot be unlocked anymore, 682*5ffd83dbSDimitry Andric // it can still participate in lock order reversal resolution. 683*5ffd83dbSDimitry Andric 6840b57cec5SDimitry Andric C.addTransition(State); 6850b57cec5SDimitry Andric } 6860b57cec5SDimitry Andric 687*5ffd83dbSDimitry Andric ProgramStateRef PthreadLockChecker::checkRegionChanges( 688*5ffd83dbSDimitry Andric ProgramStateRef State, const InvalidatedSymbols *Symbols, 689*5ffd83dbSDimitry Andric ArrayRef<const MemRegion *> ExplicitRegions, 690*5ffd83dbSDimitry Andric ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx, 691*5ffd83dbSDimitry Andric const CallEvent *Call) const { 692*5ffd83dbSDimitry Andric 693*5ffd83dbSDimitry Andric bool IsLibraryFunction = false; 694*5ffd83dbSDimitry Andric if (Call && Call->isGlobalCFunction()) { 695*5ffd83dbSDimitry Andric // Avoid invalidating mutex state when a known supported function is called. 696*5ffd83dbSDimitry Andric if (PThreadCallbacks.lookup(*Call) || FuchsiaCallbacks.lookup(*Call) || 697*5ffd83dbSDimitry Andric C11Callbacks.lookup(*Call)) 698*5ffd83dbSDimitry Andric return State; 699*5ffd83dbSDimitry Andric 700*5ffd83dbSDimitry Andric if (Call->isInSystemHeader()) 701*5ffd83dbSDimitry Andric IsLibraryFunction = true; 702*5ffd83dbSDimitry Andric } 703*5ffd83dbSDimitry Andric 704*5ffd83dbSDimitry Andric for (auto R : Regions) { 705*5ffd83dbSDimitry Andric // We assume that system library function wouldn't touch the mutex unless 706*5ffd83dbSDimitry Andric // it takes the mutex explicitly as an argument. 707*5ffd83dbSDimitry Andric // FIXME: This is a bit quadratic. 708*5ffd83dbSDimitry Andric if (IsLibraryFunction && 709*5ffd83dbSDimitry Andric std::find(ExplicitRegions.begin(), ExplicitRegions.end(), R) == 710*5ffd83dbSDimitry Andric ExplicitRegions.end()) 711*5ffd83dbSDimitry Andric continue; 712*5ffd83dbSDimitry Andric 713*5ffd83dbSDimitry Andric State = State->remove<LockMap>(R); 714*5ffd83dbSDimitry Andric State = State->remove<DestroyRetVal>(R); 715*5ffd83dbSDimitry Andric 716*5ffd83dbSDimitry Andric // TODO: We need to invalidate the lock stack as well. This is tricky 717*5ffd83dbSDimitry Andric // to implement correctly and efficiently though, because the effects 718*5ffd83dbSDimitry Andric // of mutex escapes on lock order may be fairly varied. 719*5ffd83dbSDimitry Andric } 720*5ffd83dbSDimitry Andric 721*5ffd83dbSDimitry Andric return State; 722*5ffd83dbSDimitry Andric } 723*5ffd83dbSDimitry Andric 724*5ffd83dbSDimitry Andric void ento::registerPthreadLockBase(CheckerManager &mgr) { 7250b57cec5SDimitry Andric mgr.registerChecker<PthreadLockChecker>(); 7260b57cec5SDimitry Andric } 7270b57cec5SDimitry Andric 728*5ffd83dbSDimitry Andric bool ento::shouldRegisterPthreadLockBase(const CheckerManager &mgr) { return true; } 729*5ffd83dbSDimitry Andric 730*5ffd83dbSDimitry Andric #define REGISTER_CHECKER(name) \ 731*5ffd83dbSDimitry Andric void ento::register##name(CheckerManager &mgr) { \ 732*5ffd83dbSDimitry Andric PthreadLockChecker *checker = mgr.getChecker<PthreadLockChecker>(); \ 733*5ffd83dbSDimitry Andric checker->ChecksEnabled[PthreadLockChecker::CK_##name] = true; \ 734*5ffd83dbSDimitry Andric checker->CheckNames[PthreadLockChecker::CK_##name] = \ 735*5ffd83dbSDimitry Andric mgr.getCurrentCheckerName(); \ 736*5ffd83dbSDimitry Andric } \ 737*5ffd83dbSDimitry Andric \ 738*5ffd83dbSDimitry Andric bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } 739*5ffd83dbSDimitry Andric 740*5ffd83dbSDimitry Andric REGISTER_CHECKER(PthreadLockChecker) 741*5ffd83dbSDimitry Andric REGISTER_CHECKER(FuchsiaLockChecker) 742*5ffd83dbSDimitry Andric REGISTER_CHECKER(C11LockChecker) 743