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 // 95ffd83dbSDimitry Andric // This file defines: 105ffd83dbSDimitry Andric // * PthreadLockChecker, a simple lock -> unlock checker. 115ffd83dbSDimitry Andric // Which also checks for XNU locks, which behave similarly enough to share 125ffd83dbSDimitry Andric // code. 135ffd83dbSDimitry Andric // * FuchsiaLocksChecker, which is also rather similar. 145ffd83dbSDimitry Andric // * C11LockChecker which also closely follows Pthread semantics. 155ffd83dbSDimitry Andric // 165ffd83dbSDimitry 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" 24349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" 255ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 260b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric using namespace clang; 290b57cec5SDimitry Andric using namespace ento; 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric namespace { 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric struct LockState { 340b57cec5SDimitry Andric enum Kind { 350b57cec5SDimitry Andric Destroyed, 360b57cec5SDimitry Andric Locked, 370b57cec5SDimitry Andric Unlocked, 380b57cec5SDimitry Andric UntouchedAndPossiblyDestroyed, 390b57cec5SDimitry Andric UnlockedAndPossiblyDestroyed 400b57cec5SDimitry Andric } K; 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric private: 430b57cec5SDimitry Andric LockState(Kind K) : K(K) {} 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric public: 460b57cec5SDimitry Andric static LockState getLocked() { return LockState(Locked); } 470b57cec5SDimitry Andric static LockState getUnlocked() { return LockState(Unlocked); } 480b57cec5SDimitry Andric static LockState getDestroyed() { return LockState(Destroyed); } 490b57cec5SDimitry Andric static LockState getUntouchedAndPossiblyDestroyed() { 500b57cec5SDimitry Andric return LockState(UntouchedAndPossiblyDestroyed); 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric static LockState getUnlockedAndPossiblyDestroyed() { 530b57cec5SDimitry Andric return LockState(UnlockedAndPossiblyDestroyed); 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 565ffd83dbSDimitry Andric bool operator==(const LockState &X) const { return K == X.K; } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric bool isLocked() const { return K == Locked; } 590b57cec5SDimitry Andric bool isUnlocked() const { return K == Unlocked; } 600b57cec5SDimitry Andric bool isDestroyed() const { return K == Destroyed; } 610b57cec5SDimitry Andric bool isUntouchedAndPossiblyDestroyed() const { 620b57cec5SDimitry Andric return K == UntouchedAndPossiblyDestroyed; 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric bool isUnlockedAndPossiblyDestroyed() const { 650b57cec5SDimitry Andric return K == UnlockedAndPossiblyDestroyed; 660b57cec5SDimitry Andric } 670b57cec5SDimitry Andric 685ffd83dbSDimitry Andric void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); } 690b57cec5SDimitry Andric }; 700b57cec5SDimitry Andric 715ffd83dbSDimitry Andric class PthreadLockChecker : public Checker<check::PostCall, check::DeadSymbols, 725ffd83dbSDimitry Andric check::RegionChanges> { 730b57cec5SDimitry Andric public: 745ffd83dbSDimitry Andric enum LockingSemantics { NotApplicable = 0, PthreadSemantics, XNUSemantics }; 755ffd83dbSDimitry Andric enum CheckerKind { 765ffd83dbSDimitry Andric CK_PthreadLockChecker, 775ffd83dbSDimitry Andric CK_FuchsiaLockChecker, 785ffd83dbSDimitry Andric CK_C11LockChecker, 795ffd83dbSDimitry Andric CK_NumCheckKinds 805ffd83dbSDimitry Andric }; 8181ad6265SDimitry Andric bool ChecksEnabled[CK_NumCheckKinds] = {false}; 825ffd83dbSDimitry Andric CheckerNameRef CheckNames[CK_NumCheckKinds]; 830b57cec5SDimitry Andric 845ffd83dbSDimitry Andric private: 855ffd83dbSDimitry Andric typedef void (PthreadLockChecker::*FnCheck)(const CallEvent &Call, 865ffd83dbSDimitry Andric CheckerContext &C, 87e8d8bef9SDimitry Andric CheckerKind CheckKind) const; 885ffd83dbSDimitry Andric CallDescriptionMap<FnCheck> PThreadCallbacks = { 895ffd83dbSDimitry Andric // Init. 90*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"pthread_mutex_init"}, 2}, 91*0fca6ea1SDimitry Andric &PthreadLockChecker::InitAnyLock}, 925ffd83dbSDimitry Andric // TODO: pthread_rwlock_init(2 arguments). 935ffd83dbSDimitry Andric // TODO: lck_mtx_init(3 arguments). 945ffd83dbSDimitry Andric // TODO: lck_mtx_alloc_init(2 arguments) => returns the mutex. 955ffd83dbSDimitry Andric // TODO: lck_rw_init(3 arguments). 965ffd83dbSDimitry Andric // TODO: lck_rw_alloc_init(2 arguments) => returns the mutex. 970b57cec5SDimitry Andric 985ffd83dbSDimitry Andric // Acquire. 99*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"pthread_mutex_lock"}, 1}, 100*0fca6ea1SDimitry Andric &PthreadLockChecker::AcquirePthreadLock}, 101*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"pthread_rwlock_rdlock"}, 1}, 102*0fca6ea1SDimitry Andric &PthreadLockChecker::AcquirePthreadLock}, 103*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"pthread_rwlock_wrlock"}, 1}, 104*0fca6ea1SDimitry Andric &PthreadLockChecker::AcquirePthreadLock}, 105*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"lck_mtx_lock"}, 1}, 106*0fca6ea1SDimitry Andric &PthreadLockChecker::AcquireXNULock}, 107*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"lck_rw_lock_exclusive"}, 1}, 108*0fca6ea1SDimitry Andric &PthreadLockChecker::AcquireXNULock}, 109*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"lck_rw_lock_shared"}, 1}, 110*0fca6ea1SDimitry Andric &PthreadLockChecker::AcquireXNULock}, 1115ffd83dbSDimitry Andric 1125ffd83dbSDimitry Andric // Try. 113*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"pthread_mutex_trylock"}, 1}, 114*0fca6ea1SDimitry Andric &PthreadLockChecker::TryPthreadLock}, 115*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"pthread_rwlock_tryrdlock"}, 1}, 116*0fca6ea1SDimitry Andric &PthreadLockChecker::TryPthreadLock}, 117*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"pthread_rwlock_trywrlock"}, 1}, 118*0fca6ea1SDimitry Andric &PthreadLockChecker::TryPthreadLock}, 119*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"lck_mtx_try_lock"}, 1}, 120*0fca6ea1SDimitry Andric &PthreadLockChecker::TryXNULock}, 121*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"lck_rw_try_lock_exclusive"}, 1}, 122*0fca6ea1SDimitry Andric &PthreadLockChecker::TryXNULock}, 123*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"lck_rw_try_lock_shared"}, 1}, 124*0fca6ea1SDimitry Andric &PthreadLockChecker::TryXNULock}, 1255ffd83dbSDimitry Andric 1265ffd83dbSDimitry Andric // Release. 127*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"pthread_mutex_unlock"}, 1}, 128*0fca6ea1SDimitry Andric &PthreadLockChecker::ReleaseAnyLock}, 129*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"pthread_rwlock_unlock"}, 1}, 130*0fca6ea1SDimitry Andric &PthreadLockChecker::ReleaseAnyLock}, 131*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"lck_mtx_unlock"}, 1}, 132*0fca6ea1SDimitry Andric &PthreadLockChecker::ReleaseAnyLock}, 133*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"lck_rw_unlock_exclusive"}, 1}, 134*0fca6ea1SDimitry Andric &PthreadLockChecker::ReleaseAnyLock}, 135*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"lck_rw_unlock_shared"}, 1}, 136*0fca6ea1SDimitry Andric &PthreadLockChecker::ReleaseAnyLock}, 137*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"lck_rw_done"}, 1}, 138*0fca6ea1SDimitry Andric &PthreadLockChecker::ReleaseAnyLock}, 1395ffd83dbSDimitry Andric 1405ffd83dbSDimitry Andric // Destroy. 141*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"pthread_mutex_destroy"}, 1}, 142*0fca6ea1SDimitry Andric &PthreadLockChecker::DestroyPthreadLock}, 143*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"lck_mtx_destroy"}, 2}, 144*0fca6ea1SDimitry Andric &PthreadLockChecker::DestroyXNULock}, 1455ffd83dbSDimitry Andric // TODO: pthread_rwlock_destroy(1 argument). 1465ffd83dbSDimitry Andric // TODO: lck_rw_destroy(2 arguments). 1475ffd83dbSDimitry Andric }; 1485ffd83dbSDimitry Andric 1495ffd83dbSDimitry Andric CallDescriptionMap<FnCheck> FuchsiaCallbacks = { 1505ffd83dbSDimitry Andric // Init. 151*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"spin_lock_init"}, 1}, 152*0fca6ea1SDimitry Andric &PthreadLockChecker::InitAnyLock}, 1535ffd83dbSDimitry Andric 1545ffd83dbSDimitry Andric // Acquire. 155*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"spin_lock"}, 1}, 156*0fca6ea1SDimitry Andric &PthreadLockChecker::AcquirePthreadLock}, 157*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"spin_lock_save"}, 3}, 158*0fca6ea1SDimitry Andric &PthreadLockChecker::AcquirePthreadLock}, 159*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"sync_mutex_lock"}, 1}, 160*0fca6ea1SDimitry Andric &PthreadLockChecker::AcquirePthreadLock}, 161*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"sync_mutex_lock_with_waiter"}, 1}, 1625ffd83dbSDimitry Andric &PthreadLockChecker::AcquirePthreadLock}, 1635ffd83dbSDimitry Andric 1645ffd83dbSDimitry Andric // Try. 165*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"spin_trylock"}, 1}, 166*0fca6ea1SDimitry Andric &PthreadLockChecker::TryFuchsiaLock}, 167*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"sync_mutex_trylock"}, 1}, 168*0fca6ea1SDimitry Andric &PthreadLockChecker::TryFuchsiaLock}, 169*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"sync_mutex_timedlock"}, 2}, 170*0fca6ea1SDimitry Andric &PthreadLockChecker::TryFuchsiaLock}, 1715ffd83dbSDimitry Andric 1725ffd83dbSDimitry Andric // Release. 173*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"spin_unlock"}, 1}, 174*0fca6ea1SDimitry Andric &PthreadLockChecker::ReleaseAnyLock}, 175*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"spin_unlock_restore"}, 3}, 176*0fca6ea1SDimitry Andric &PthreadLockChecker::ReleaseAnyLock}, 177*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"sync_mutex_unlock"}, 1}, 178*0fca6ea1SDimitry Andric &PthreadLockChecker::ReleaseAnyLock}, 1795ffd83dbSDimitry Andric }; 1805ffd83dbSDimitry Andric 1815ffd83dbSDimitry Andric CallDescriptionMap<FnCheck> C11Callbacks = { 1825ffd83dbSDimitry Andric // Init. 183*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"mtx_init"}, 2}, &PthreadLockChecker::InitAnyLock}, 1845ffd83dbSDimitry Andric 1855ffd83dbSDimitry Andric // Acquire. 186*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"mtx_lock"}, 1}, 187*0fca6ea1SDimitry Andric &PthreadLockChecker::AcquirePthreadLock}, 1885ffd83dbSDimitry Andric 1895ffd83dbSDimitry Andric // Try. 190*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"mtx_trylock"}, 1}, &PthreadLockChecker::TryC11Lock}, 191*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"mtx_timedlock"}, 2}, &PthreadLockChecker::TryC11Lock}, 1925ffd83dbSDimitry Andric 1935ffd83dbSDimitry Andric // Release. 194*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"mtx_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock}, 1955ffd83dbSDimitry Andric 1965ffd83dbSDimitry Andric // Destroy 197*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"mtx_destroy"}, 1}, 198*0fca6ea1SDimitry Andric &PthreadLockChecker::DestroyPthreadLock}, 1995ffd83dbSDimitry Andric }; 2005ffd83dbSDimitry Andric 2010b57cec5SDimitry Andric ProgramStateRef resolvePossiblyDestroyedMutex(ProgramStateRef state, 2020b57cec5SDimitry Andric const MemRegion *lockR, 2030b57cec5SDimitry Andric const SymbolRef *sym) const; 204e8d8bef9SDimitry Andric void reportBug(CheckerContext &C, std::unique_ptr<BugType> BT[], 205e8d8bef9SDimitry Andric const Expr *MtxExpr, CheckerKind CheckKind, 206e8d8bef9SDimitry Andric StringRef Desc) const; 2075ffd83dbSDimitry Andric 2085ffd83dbSDimitry Andric // Init. 2095ffd83dbSDimitry Andric void InitAnyLock(const CallEvent &Call, CheckerContext &C, 210e8d8bef9SDimitry Andric CheckerKind CheckKind) const; 211e8d8bef9SDimitry Andric void InitLockAux(const CallEvent &Call, CheckerContext &C, 212e8d8bef9SDimitry Andric const Expr *MtxExpr, SVal MtxVal, 213e8d8bef9SDimitry Andric CheckerKind CheckKind) const; 2145ffd83dbSDimitry Andric 2155ffd83dbSDimitry Andric // Lock, Try-lock. 2165ffd83dbSDimitry Andric void AcquirePthreadLock(const CallEvent &Call, CheckerContext &C, 217e8d8bef9SDimitry Andric CheckerKind CheckKind) const; 2185ffd83dbSDimitry Andric void AcquireXNULock(const CallEvent &Call, CheckerContext &C, 219e8d8bef9SDimitry Andric CheckerKind CheckKind) const; 2205ffd83dbSDimitry Andric void TryPthreadLock(const CallEvent &Call, CheckerContext &C, 221e8d8bef9SDimitry Andric CheckerKind CheckKind) const; 2225ffd83dbSDimitry Andric void TryXNULock(const CallEvent &Call, CheckerContext &C, 223e8d8bef9SDimitry Andric CheckerKind CheckKind) const; 2245ffd83dbSDimitry Andric void TryFuchsiaLock(const CallEvent &Call, CheckerContext &C, 225e8d8bef9SDimitry Andric CheckerKind CheckKind) const; 2265ffd83dbSDimitry Andric void TryC11Lock(const CallEvent &Call, CheckerContext &C, 227e8d8bef9SDimitry Andric CheckerKind CheckKind) const; 228e8d8bef9SDimitry Andric void AcquireLockAux(const CallEvent &Call, CheckerContext &C, 229e8d8bef9SDimitry Andric const Expr *MtxExpr, SVal MtxVal, bool IsTryLock, 230e8d8bef9SDimitry Andric LockingSemantics Semantics, CheckerKind CheckKind) const; 2315ffd83dbSDimitry Andric 2325ffd83dbSDimitry Andric // Release. 2335ffd83dbSDimitry Andric void ReleaseAnyLock(const CallEvent &Call, CheckerContext &C, 234e8d8bef9SDimitry Andric CheckerKind CheckKind) const; 235e8d8bef9SDimitry Andric void ReleaseLockAux(const CallEvent &Call, CheckerContext &C, 236e8d8bef9SDimitry Andric const Expr *MtxExpr, SVal MtxVal, 237e8d8bef9SDimitry Andric CheckerKind CheckKind) const; 2385ffd83dbSDimitry Andric 2395ffd83dbSDimitry Andric // Destroy. 2405ffd83dbSDimitry Andric void DestroyPthreadLock(const CallEvent &Call, CheckerContext &C, 241e8d8bef9SDimitry Andric CheckerKind CheckKind) const; 2425ffd83dbSDimitry Andric void DestroyXNULock(const CallEvent &Call, CheckerContext &C, 243e8d8bef9SDimitry Andric CheckerKind CheckKind) const; 244e8d8bef9SDimitry Andric void DestroyLockAux(const CallEvent &Call, CheckerContext &C, 245e8d8bef9SDimitry Andric const Expr *MtxExpr, SVal MtxVal, 246e8d8bef9SDimitry Andric LockingSemantics Semantics, CheckerKind CheckKind) const; 2475ffd83dbSDimitry Andric 2485ffd83dbSDimitry Andric public: 2495ffd83dbSDimitry Andric void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 2505ffd83dbSDimitry Andric void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; 2515ffd83dbSDimitry Andric ProgramStateRef 2525ffd83dbSDimitry Andric checkRegionChanges(ProgramStateRef State, const InvalidatedSymbols *Symbols, 2535ffd83dbSDimitry Andric ArrayRef<const MemRegion *> ExplicitRegions, 2545ffd83dbSDimitry Andric ArrayRef<const MemRegion *> Regions, 2555ffd83dbSDimitry Andric const LocationContext *LCtx, const CallEvent *Call) const; 2565ffd83dbSDimitry Andric void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, 2575ffd83dbSDimitry Andric const char *Sep) const override; 2585ffd83dbSDimitry Andric 2595ffd83dbSDimitry Andric private: 2605ffd83dbSDimitry Andric mutable std::unique_ptr<BugType> BT_doublelock[CK_NumCheckKinds]; 2615ffd83dbSDimitry Andric mutable std::unique_ptr<BugType> BT_doubleunlock[CK_NumCheckKinds]; 2625ffd83dbSDimitry Andric mutable std::unique_ptr<BugType> BT_destroylock[CK_NumCheckKinds]; 2635ffd83dbSDimitry Andric mutable std::unique_ptr<BugType> BT_initlock[CK_NumCheckKinds]; 2645ffd83dbSDimitry Andric mutable std::unique_ptr<BugType> BT_lor[CK_NumCheckKinds]; 2655ffd83dbSDimitry Andric 266e8d8bef9SDimitry Andric void initBugType(CheckerKind CheckKind) const { 267e8d8bef9SDimitry Andric if (BT_doublelock[CheckKind]) 2685ffd83dbSDimitry Andric return; 269e8d8bef9SDimitry Andric BT_doublelock[CheckKind].reset( 270e8d8bef9SDimitry Andric new BugType{CheckNames[CheckKind], "Double locking", "Lock checker"}); 271e8d8bef9SDimitry Andric BT_doubleunlock[CheckKind].reset( 272e8d8bef9SDimitry Andric new BugType{CheckNames[CheckKind], "Double unlocking", "Lock checker"}); 273e8d8bef9SDimitry Andric BT_destroylock[CheckKind].reset(new BugType{ 274e8d8bef9SDimitry Andric CheckNames[CheckKind], "Use destroyed lock", "Lock checker"}); 275e8d8bef9SDimitry Andric BT_initlock[CheckKind].reset(new BugType{ 276e8d8bef9SDimitry Andric CheckNames[CheckKind], "Init invalid lock", "Lock checker"}); 277e8d8bef9SDimitry Andric BT_lor[CheckKind].reset(new BugType{CheckNames[CheckKind], 2785ffd83dbSDimitry Andric "Lock order reversal", "Lock checker"}); 2795ffd83dbSDimitry Andric } 2800b57cec5SDimitry Andric }; 2810b57cec5SDimitry Andric } // end anonymous namespace 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric // A stack of locks for tracking lock-unlock order. 2840b57cec5SDimitry Andric REGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *) 2850b57cec5SDimitry Andric 2860b57cec5SDimitry Andric // An entry for tracking lock states. 2870b57cec5SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(LockMap, const MemRegion *, LockState) 2880b57cec5SDimitry Andric 2890b57cec5SDimitry Andric // Return values for unresolved calls to pthread_mutex_destroy(). 2900b57cec5SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(DestroyRetVal, const MemRegion *, SymbolRef) 2910b57cec5SDimitry Andric 2925ffd83dbSDimitry Andric void PthreadLockChecker::checkPostCall(const CallEvent &Call, 2930b57cec5SDimitry Andric CheckerContext &C) const { 2945ffd83dbSDimitry Andric // FIXME: Try to handle cases when the implementation was inlined rather 2955ffd83dbSDimitry Andric // than just giving up. 296*0fca6ea1SDimitry Andric if (C.wasInlined) 2970b57cec5SDimitry Andric return; 2980b57cec5SDimitry Andric 2995ffd83dbSDimitry Andric if (const FnCheck *Callback = PThreadCallbacks.lookup(Call)) 3005ffd83dbSDimitry Andric (this->**Callback)(Call, C, CK_PthreadLockChecker); 3015ffd83dbSDimitry Andric else if (const FnCheck *Callback = FuchsiaCallbacks.lookup(Call)) 3025ffd83dbSDimitry Andric (this->**Callback)(Call, C, CK_FuchsiaLockChecker); 3035ffd83dbSDimitry Andric else if (const FnCheck *Callback = C11Callbacks.lookup(Call)) 3045ffd83dbSDimitry Andric (this->**Callback)(Call, C, CK_C11LockChecker); 3050b57cec5SDimitry Andric } 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric // When a lock is destroyed, in some semantics(like PthreadSemantics) we are not 3080b57cec5SDimitry Andric // sure if the destroy call has succeeded or failed, and the lock enters one of 3090b57cec5SDimitry Andric // the 'possibly destroyed' state. There is a short time frame for the 3100b57cec5SDimitry Andric // programmer to check the return value to see if the lock was successfully 3110b57cec5SDimitry Andric // destroyed. Before we model the next operation over that lock, we call this 3120b57cec5SDimitry Andric // function to see if the return value was checked by now and set the lock state 3130b57cec5SDimitry Andric // - either to destroyed state or back to its previous state. 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric // In PthreadSemantics, pthread_mutex_destroy() returns zero if the lock is 3160b57cec5SDimitry Andric // successfully destroyed and it returns a non-zero value otherwise. 3170b57cec5SDimitry Andric ProgramStateRef PthreadLockChecker::resolvePossiblyDestroyedMutex( 3180b57cec5SDimitry Andric ProgramStateRef state, const MemRegion *lockR, const SymbolRef *sym) const { 3190b57cec5SDimitry Andric const LockState *lstate = state->get<LockMap>(lockR); 3200b57cec5SDimitry Andric // Existence in DestroyRetVal ensures existence in LockMap. 3210b57cec5SDimitry Andric // Existence in Destroyed also ensures that the lock state for lockR is either 3220b57cec5SDimitry Andric // UntouchedAndPossiblyDestroyed or UnlockedAndPossiblyDestroyed. 32306c3fb27SDimitry Andric assert(lstate); 3240b57cec5SDimitry Andric assert(lstate->isUntouchedAndPossiblyDestroyed() || 3250b57cec5SDimitry Andric lstate->isUnlockedAndPossiblyDestroyed()); 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric ConstraintManager &CMgr = state->getConstraintManager(); 3280b57cec5SDimitry Andric ConditionTruthVal retZero = CMgr.isNull(state, *sym); 3290b57cec5SDimitry Andric if (retZero.isConstrainedFalse()) { 3300b57cec5SDimitry Andric if (lstate->isUntouchedAndPossiblyDestroyed()) 3310b57cec5SDimitry Andric state = state->remove<LockMap>(lockR); 3320b57cec5SDimitry Andric else if (lstate->isUnlockedAndPossiblyDestroyed()) 3330b57cec5SDimitry Andric state = state->set<LockMap>(lockR, LockState::getUnlocked()); 3340b57cec5SDimitry Andric } else 3350b57cec5SDimitry Andric state = state->set<LockMap>(lockR, LockState::getDestroyed()); 3360b57cec5SDimitry Andric 3370b57cec5SDimitry Andric // Removing the map entry (lockR, sym) from DestroyRetVal as the lock state is 3380b57cec5SDimitry Andric // now resolved. 3390b57cec5SDimitry Andric state = state->remove<DestroyRetVal>(lockR); 3400b57cec5SDimitry Andric return state; 3410b57cec5SDimitry Andric } 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric void PthreadLockChecker::printState(raw_ostream &Out, ProgramStateRef State, 3440b57cec5SDimitry Andric const char *NL, const char *Sep) const { 3450b57cec5SDimitry Andric LockMapTy LM = State->get<LockMap>(); 3460b57cec5SDimitry Andric if (!LM.isEmpty()) { 3470b57cec5SDimitry Andric Out << Sep << "Mutex states:" << NL; 3480b57cec5SDimitry Andric for (auto I : LM) { 3490b57cec5SDimitry Andric I.first->dumpToStream(Out); 3500b57cec5SDimitry Andric if (I.second.isLocked()) 3510b57cec5SDimitry Andric Out << ": locked"; 3520b57cec5SDimitry Andric else if (I.second.isUnlocked()) 3530b57cec5SDimitry Andric Out << ": unlocked"; 3540b57cec5SDimitry Andric else if (I.second.isDestroyed()) 3550b57cec5SDimitry Andric Out << ": destroyed"; 3560b57cec5SDimitry Andric else if (I.second.isUntouchedAndPossiblyDestroyed()) 3570b57cec5SDimitry Andric Out << ": not tracked, possibly destroyed"; 3580b57cec5SDimitry Andric else if (I.second.isUnlockedAndPossiblyDestroyed()) 3590b57cec5SDimitry Andric Out << ": unlocked, possibly destroyed"; 3600b57cec5SDimitry Andric Out << NL; 3610b57cec5SDimitry Andric } 3620b57cec5SDimitry Andric } 3630b57cec5SDimitry Andric 3640b57cec5SDimitry Andric LockSetTy LS = State->get<LockSet>(); 3650b57cec5SDimitry Andric if (!LS.isEmpty()) { 3660b57cec5SDimitry Andric Out << Sep << "Mutex lock order:" << NL; 3670b57cec5SDimitry Andric for (auto I : LS) { 3680b57cec5SDimitry Andric I->dumpToStream(Out); 3690b57cec5SDimitry Andric Out << NL; 3700b57cec5SDimitry Andric } 3710b57cec5SDimitry Andric } 3720b57cec5SDimitry Andric 373fe6060f1SDimitry Andric DestroyRetValTy DRV = State->get<DestroyRetVal>(); 374fe6060f1SDimitry Andric if (!DRV.isEmpty()) { 375fe6060f1SDimitry Andric Out << Sep << "Mutexes in unresolved possibly destroyed state:" << NL; 376fe6060f1SDimitry Andric for (auto I : DRV) { 377fe6060f1SDimitry Andric I.first->dumpToStream(Out); 378fe6060f1SDimitry Andric Out << ": "; 379fe6060f1SDimitry Andric I.second->dumpToStream(Out); 380fe6060f1SDimitry Andric Out << NL; 381fe6060f1SDimitry Andric } 382fe6060f1SDimitry Andric } 3830b57cec5SDimitry Andric } 3840b57cec5SDimitry Andric 3855ffd83dbSDimitry Andric void PthreadLockChecker::AcquirePthreadLock(const CallEvent &Call, 3865ffd83dbSDimitry Andric CheckerContext &C, 387e8d8bef9SDimitry Andric CheckerKind CheckKind) const { 388e8d8bef9SDimitry Andric AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), false, 389e8d8bef9SDimitry Andric PthreadSemantics, CheckKind); 3905ffd83dbSDimitry Andric } 3915ffd83dbSDimitry Andric 3925ffd83dbSDimitry Andric void PthreadLockChecker::AcquireXNULock(const CallEvent &Call, 3935ffd83dbSDimitry Andric CheckerContext &C, 394e8d8bef9SDimitry Andric CheckerKind CheckKind) const { 395e8d8bef9SDimitry Andric AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), false, 396e8d8bef9SDimitry Andric XNUSemantics, CheckKind); 3975ffd83dbSDimitry Andric } 3985ffd83dbSDimitry Andric 3995ffd83dbSDimitry Andric void PthreadLockChecker::TryPthreadLock(const CallEvent &Call, 4005ffd83dbSDimitry Andric CheckerContext &C, 401e8d8bef9SDimitry Andric CheckerKind CheckKind) const { 402e8d8bef9SDimitry Andric AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), true, 403e8d8bef9SDimitry Andric PthreadSemantics, CheckKind); 4045ffd83dbSDimitry Andric } 4055ffd83dbSDimitry Andric 4065ffd83dbSDimitry Andric void PthreadLockChecker::TryXNULock(const CallEvent &Call, CheckerContext &C, 407e8d8bef9SDimitry Andric CheckerKind CheckKind) const { 408e8d8bef9SDimitry Andric AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), true, 409e8d8bef9SDimitry Andric PthreadSemantics, CheckKind); 4105ffd83dbSDimitry Andric } 4115ffd83dbSDimitry Andric 4125ffd83dbSDimitry Andric void PthreadLockChecker::TryFuchsiaLock(const CallEvent &Call, 4135ffd83dbSDimitry Andric CheckerContext &C, 414e8d8bef9SDimitry Andric CheckerKind CheckKind) const { 415e8d8bef9SDimitry Andric AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), true, 416e8d8bef9SDimitry Andric PthreadSemantics, CheckKind); 4175ffd83dbSDimitry Andric } 4185ffd83dbSDimitry Andric 4195ffd83dbSDimitry Andric void PthreadLockChecker::TryC11Lock(const CallEvent &Call, CheckerContext &C, 420e8d8bef9SDimitry Andric CheckerKind CheckKind) const { 421e8d8bef9SDimitry Andric AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), true, 422e8d8bef9SDimitry Andric PthreadSemantics, CheckKind); 4235ffd83dbSDimitry Andric } 4245ffd83dbSDimitry Andric 4255ffd83dbSDimitry Andric void PthreadLockChecker::AcquireLockAux(const CallEvent &Call, 426e8d8bef9SDimitry Andric CheckerContext &C, const Expr *MtxExpr, 427e8d8bef9SDimitry Andric SVal MtxVal, bool IsTryLock, 428e8d8bef9SDimitry Andric enum LockingSemantics Semantics, 429e8d8bef9SDimitry Andric CheckerKind CheckKind) const { 430e8d8bef9SDimitry Andric if (!ChecksEnabled[CheckKind]) 4315ffd83dbSDimitry Andric return; 4320b57cec5SDimitry Andric 433e8d8bef9SDimitry Andric const MemRegion *lockR = MtxVal.getAsRegion(); 4340b57cec5SDimitry Andric if (!lockR) 4350b57cec5SDimitry Andric return; 4360b57cec5SDimitry Andric 4370b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 4380b57cec5SDimitry Andric const SymbolRef *sym = state->get<DestroyRetVal>(lockR); 4390b57cec5SDimitry Andric if (sym) 4400b57cec5SDimitry Andric state = resolvePossiblyDestroyedMutex(state, lockR, sym); 4410b57cec5SDimitry Andric 4420b57cec5SDimitry Andric if (const LockState *LState = state->get<LockMap>(lockR)) { 4430b57cec5SDimitry Andric if (LState->isLocked()) { 444e8d8bef9SDimitry Andric reportBug(C, BT_doublelock, MtxExpr, CheckKind, 445e8d8bef9SDimitry Andric "This lock has already been acquired"); 4460b57cec5SDimitry Andric return; 4470b57cec5SDimitry Andric } else if (LState->isDestroyed()) { 448e8d8bef9SDimitry Andric reportBug(C, BT_destroylock, MtxExpr, CheckKind, 449e8d8bef9SDimitry Andric "This lock has already been destroyed"); 4500b57cec5SDimitry Andric return; 4510b57cec5SDimitry Andric } 4520b57cec5SDimitry Andric } 4530b57cec5SDimitry Andric 4540b57cec5SDimitry Andric ProgramStateRef lockSucc = state; 455e8d8bef9SDimitry Andric if (IsTryLock) { 4560b57cec5SDimitry Andric // Bifurcate the state, and allow a mode where the lock acquisition fails. 4575ffd83dbSDimitry Andric SVal RetVal = Call.getReturnValue(); 4585ffd83dbSDimitry Andric if (auto DefinedRetVal = RetVal.getAs<DefinedSVal>()) { 4590b57cec5SDimitry Andric ProgramStateRef lockFail; 460e8d8bef9SDimitry Andric switch (Semantics) { 4610b57cec5SDimitry Andric case PthreadSemantics: 4625ffd83dbSDimitry Andric std::tie(lockFail, lockSucc) = state->assume(*DefinedRetVal); 4630b57cec5SDimitry Andric break; 4640b57cec5SDimitry Andric case XNUSemantics: 4655ffd83dbSDimitry Andric std::tie(lockSucc, lockFail) = state->assume(*DefinedRetVal); 4660b57cec5SDimitry Andric break; 4670b57cec5SDimitry Andric default: 4680b57cec5SDimitry Andric llvm_unreachable("Unknown tryLock locking semantics"); 4690b57cec5SDimitry Andric } 4700b57cec5SDimitry Andric assert(lockFail && lockSucc); 4710b57cec5SDimitry Andric C.addTransition(lockFail); 4725ffd83dbSDimitry Andric } 4735ffd83dbSDimitry Andric // We might want to handle the case when the mutex lock function was inlined 4745ffd83dbSDimitry Andric // and returned an Unknown or Undefined value. 475e8d8bef9SDimitry Andric } else if (Semantics == PthreadSemantics) { 4760b57cec5SDimitry Andric // Assume that the return value was 0. 4775ffd83dbSDimitry Andric SVal RetVal = Call.getReturnValue(); 4785ffd83dbSDimitry Andric if (auto DefinedRetVal = RetVal.getAs<DefinedSVal>()) { 4795ffd83dbSDimitry Andric // FIXME: If the lock function was inlined and returned true, 4805ffd83dbSDimitry Andric // we need to behave sanely - at least generate sink. 4815ffd83dbSDimitry Andric lockSucc = state->assume(*DefinedRetVal, false); 4820b57cec5SDimitry Andric assert(lockSucc); 4835ffd83dbSDimitry Andric } 4845ffd83dbSDimitry Andric // We might want to handle the case when the mutex lock function was inlined 4855ffd83dbSDimitry Andric // and returned an Unknown or Undefined value. 4860b57cec5SDimitry Andric } else { 4870b57cec5SDimitry Andric // XNU locking semantics return void on non-try locks 488e8d8bef9SDimitry Andric assert((Semantics == XNUSemantics) && "Unknown locking semantics"); 4890b57cec5SDimitry Andric lockSucc = state; 4900b57cec5SDimitry Andric } 4910b57cec5SDimitry Andric 4920b57cec5SDimitry Andric // Record that the lock was acquired. 4930b57cec5SDimitry Andric lockSucc = lockSucc->add<LockSet>(lockR); 4940b57cec5SDimitry Andric lockSucc = lockSucc->set<LockMap>(lockR, LockState::getLocked()); 4950b57cec5SDimitry Andric C.addTransition(lockSucc); 4960b57cec5SDimitry Andric } 4970b57cec5SDimitry Andric 4985ffd83dbSDimitry Andric void PthreadLockChecker::ReleaseAnyLock(const CallEvent &Call, 4995ffd83dbSDimitry Andric CheckerContext &C, 500e8d8bef9SDimitry Andric CheckerKind CheckKind) const { 501e8d8bef9SDimitry Andric ReleaseLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), CheckKind); 5025ffd83dbSDimitry Andric } 5035ffd83dbSDimitry Andric 5045ffd83dbSDimitry Andric void PthreadLockChecker::ReleaseLockAux(const CallEvent &Call, 505e8d8bef9SDimitry Andric CheckerContext &C, const Expr *MtxExpr, 506e8d8bef9SDimitry Andric SVal MtxVal, 507e8d8bef9SDimitry Andric CheckerKind CheckKind) const { 508e8d8bef9SDimitry Andric if (!ChecksEnabled[CheckKind]) 5095ffd83dbSDimitry Andric return; 5100b57cec5SDimitry Andric 511e8d8bef9SDimitry Andric const MemRegion *lockR = MtxVal.getAsRegion(); 5120b57cec5SDimitry Andric if (!lockR) 5130b57cec5SDimitry Andric return; 5140b57cec5SDimitry Andric 5150b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 5160b57cec5SDimitry Andric const SymbolRef *sym = state->get<DestroyRetVal>(lockR); 5170b57cec5SDimitry Andric if (sym) 5180b57cec5SDimitry Andric state = resolvePossiblyDestroyedMutex(state, lockR, sym); 5190b57cec5SDimitry Andric 5200b57cec5SDimitry Andric if (const LockState *LState = state->get<LockMap>(lockR)) { 5210b57cec5SDimitry Andric if (LState->isUnlocked()) { 522e8d8bef9SDimitry Andric reportBug(C, BT_doubleunlock, MtxExpr, CheckKind, 523e8d8bef9SDimitry Andric "This lock has already been unlocked"); 5240b57cec5SDimitry Andric return; 5250b57cec5SDimitry Andric } else if (LState->isDestroyed()) { 526e8d8bef9SDimitry Andric reportBug(C, BT_destroylock, MtxExpr, CheckKind, 527e8d8bef9SDimitry Andric "This lock has already been destroyed"); 5280b57cec5SDimitry Andric return; 5290b57cec5SDimitry Andric } 5300b57cec5SDimitry Andric } 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric LockSetTy LS = state->get<LockSet>(); 5330b57cec5SDimitry Andric 5340b57cec5SDimitry Andric if (!LS.isEmpty()) { 5350b57cec5SDimitry Andric const MemRegion *firstLockR = LS.getHead(); 5360b57cec5SDimitry Andric if (firstLockR != lockR) { 537e8d8bef9SDimitry Andric reportBug(C, BT_lor, MtxExpr, CheckKind, 538e8d8bef9SDimitry Andric "This was not the most recently acquired lock. Possible lock " 539e8d8bef9SDimitry Andric "order reversal"); 5400b57cec5SDimitry Andric return; 5410b57cec5SDimitry Andric } 5420b57cec5SDimitry Andric // Record that the lock was released. 5430b57cec5SDimitry Andric state = state->set<LockSet>(LS.getTail()); 5440b57cec5SDimitry Andric } 5450b57cec5SDimitry Andric 5460b57cec5SDimitry Andric state = state->set<LockMap>(lockR, LockState::getUnlocked()); 5470b57cec5SDimitry Andric C.addTransition(state); 5480b57cec5SDimitry Andric } 5490b57cec5SDimitry Andric 5505ffd83dbSDimitry Andric void PthreadLockChecker::DestroyPthreadLock(const CallEvent &Call, 5515ffd83dbSDimitry Andric CheckerContext &C, 552e8d8bef9SDimitry Andric CheckerKind CheckKind) const { 553e8d8bef9SDimitry Andric DestroyLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), 554e8d8bef9SDimitry Andric PthreadSemantics, CheckKind); 5555ffd83dbSDimitry Andric } 5565ffd83dbSDimitry Andric 5575ffd83dbSDimitry Andric void PthreadLockChecker::DestroyXNULock(const CallEvent &Call, 5585ffd83dbSDimitry Andric CheckerContext &C, 559e8d8bef9SDimitry Andric CheckerKind CheckKind) const { 560e8d8bef9SDimitry Andric DestroyLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), XNUSemantics, 561e8d8bef9SDimitry Andric CheckKind); 5625ffd83dbSDimitry Andric } 5635ffd83dbSDimitry Andric 5645ffd83dbSDimitry Andric void PthreadLockChecker::DestroyLockAux(const CallEvent &Call, 565e8d8bef9SDimitry Andric CheckerContext &C, const Expr *MtxExpr, 566e8d8bef9SDimitry Andric SVal MtxVal, 567e8d8bef9SDimitry Andric enum LockingSemantics Semantics, 568e8d8bef9SDimitry Andric CheckerKind CheckKind) const { 569e8d8bef9SDimitry Andric if (!ChecksEnabled[CheckKind]) 5705ffd83dbSDimitry Andric return; 5710b57cec5SDimitry Andric 572e8d8bef9SDimitry Andric const MemRegion *LockR = MtxVal.getAsRegion(); 5730b57cec5SDimitry Andric if (!LockR) 5740b57cec5SDimitry Andric return; 5750b57cec5SDimitry Andric 5760b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 5770b57cec5SDimitry Andric 5780b57cec5SDimitry Andric const SymbolRef *sym = State->get<DestroyRetVal>(LockR); 5790b57cec5SDimitry Andric if (sym) 5800b57cec5SDimitry Andric State = resolvePossiblyDestroyedMutex(State, LockR, sym); 5810b57cec5SDimitry Andric 5820b57cec5SDimitry Andric const LockState *LState = State->get<LockMap>(LockR); 5830b57cec5SDimitry Andric // Checking the return value of the destroy method only in the case of 5840b57cec5SDimitry Andric // PthreadSemantics 585e8d8bef9SDimitry Andric if (Semantics == PthreadSemantics) { 5860b57cec5SDimitry Andric if (!LState || LState->isUnlocked()) { 5875ffd83dbSDimitry Andric SymbolRef sym = Call.getReturnValue().getAsSymbol(); 5880b57cec5SDimitry Andric if (!sym) { 5890b57cec5SDimitry Andric State = State->remove<LockMap>(LockR); 5900b57cec5SDimitry Andric C.addTransition(State); 5910b57cec5SDimitry Andric return; 5920b57cec5SDimitry Andric } 5930b57cec5SDimitry Andric State = State->set<DestroyRetVal>(LockR, sym); 5940b57cec5SDimitry Andric if (LState && LState->isUnlocked()) 5950b57cec5SDimitry Andric State = State->set<LockMap>( 5960b57cec5SDimitry Andric LockR, LockState::getUnlockedAndPossiblyDestroyed()); 5970b57cec5SDimitry Andric else 5980b57cec5SDimitry Andric State = State->set<LockMap>( 5990b57cec5SDimitry Andric LockR, LockState::getUntouchedAndPossiblyDestroyed()); 6000b57cec5SDimitry Andric C.addTransition(State); 6010b57cec5SDimitry Andric return; 6020b57cec5SDimitry Andric } 6030b57cec5SDimitry Andric } else { 6040b57cec5SDimitry Andric if (!LState || LState->isUnlocked()) { 6050b57cec5SDimitry Andric State = State->set<LockMap>(LockR, LockState::getDestroyed()); 6060b57cec5SDimitry Andric C.addTransition(State); 6070b57cec5SDimitry Andric return; 6080b57cec5SDimitry Andric } 6090b57cec5SDimitry Andric } 6100b57cec5SDimitry Andric 611e8d8bef9SDimitry Andric StringRef Message = LState->isLocked() 612e8d8bef9SDimitry Andric ? "This lock is still locked" 613e8d8bef9SDimitry Andric : "This lock has already been destroyed"; 6140b57cec5SDimitry Andric 615e8d8bef9SDimitry Andric reportBug(C, BT_destroylock, MtxExpr, CheckKind, Message); 6160b57cec5SDimitry Andric } 6170b57cec5SDimitry Andric 6185ffd83dbSDimitry Andric void PthreadLockChecker::InitAnyLock(const CallEvent &Call, CheckerContext &C, 619e8d8bef9SDimitry Andric CheckerKind CheckKind) const { 620e8d8bef9SDimitry Andric InitLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), CheckKind); 6215ffd83dbSDimitry Andric } 6225ffd83dbSDimitry Andric 6235ffd83dbSDimitry Andric void PthreadLockChecker::InitLockAux(const CallEvent &Call, CheckerContext &C, 624e8d8bef9SDimitry Andric const Expr *MtxExpr, SVal MtxVal, 625e8d8bef9SDimitry Andric CheckerKind CheckKind) const { 626e8d8bef9SDimitry Andric if (!ChecksEnabled[CheckKind]) 6275ffd83dbSDimitry Andric return; 6280b57cec5SDimitry Andric 629e8d8bef9SDimitry Andric const MemRegion *LockR = MtxVal.getAsRegion(); 6300b57cec5SDimitry Andric if (!LockR) 6310b57cec5SDimitry Andric return; 6320b57cec5SDimitry Andric 6330b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 6340b57cec5SDimitry Andric 6350b57cec5SDimitry Andric const SymbolRef *sym = State->get<DestroyRetVal>(LockR); 6360b57cec5SDimitry Andric if (sym) 6370b57cec5SDimitry Andric State = resolvePossiblyDestroyedMutex(State, LockR, sym); 6380b57cec5SDimitry Andric 6390b57cec5SDimitry Andric const struct LockState *LState = State->get<LockMap>(LockR); 6400b57cec5SDimitry Andric if (!LState || LState->isDestroyed()) { 6410b57cec5SDimitry Andric State = State->set<LockMap>(LockR, LockState::getUnlocked()); 6420b57cec5SDimitry Andric C.addTransition(State); 6430b57cec5SDimitry Andric return; 6440b57cec5SDimitry Andric } 6450b57cec5SDimitry Andric 646e8d8bef9SDimitry Andric StringRef Message = LState->isLocked() 647e8d8bef9SDimitry Andric ? "This lock is still being held" 648e8d8bef9SDimitry Andric : "This lock has already been initialized"; 6490b57cec5SDimitry Andric 650e8d8bef9SDimitry Andric reportBug(C, BT_initlock, MtxExpr, CheckKind, Message); 6510b57cec5SDimitry Andric } 6520b57cec5SDimitry Andric 653e8d8bef9SDimitry Andric void PthreadLockChecker::reportBug(CheckerContext &C, 654e8d8bef9SDimitry Andric std::unique_ptr<BugType> BT[], 655e8d8bef9SDimitry Andric const Expr *MtxExpr, CheckerKind CheckKind, 656e8d8bef9SDimitry Andric StringRef Desc) const { 6570b57cec5SDimitry Andric ExplodedNode *N = C.generateErrorNode(); 6580b57cec5SDimitry Andric if (!N) 6590b57cec5SDimitry Andric return; 660e8d8bef9SDimitry Andric initBugType(CheckKind); 661e8d8bef9SDimitry Andric auto Report = 662e8d8bef9SDimitry Andric std::make_unique<PathSensitiveBugReport>(*BT[CheckKind], Desc, N); 663e8d8bef9SDimitry Andric Report->addRange(MtxExpr->getSourceRange()); 6640b57cec5SDimitry Andric C.emitReport(std::move(Report)); 6650b57cec5SDimitry Andric } 6660b57cec5SDimitry Andric 6670b57cec5SDimitry Andric void PthreadLockChecker::checkDeadSymbols(SymbolReaper &SymReaper, 6680b57cec5SDimitry Andric CheckerContext &C) const { 6690b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 6700b57cec5SDimitry Andric 6715ffd83dbSDimitry Andric for (auto I : State->get<DestroyRetVal>()) { 6725ffd83dbSDimitry Andric // Once the return value symbol dies, no more checks can be performed 6735ffd83dbSDimitry Andric // against it. See if the return value was checked before this point. 6745ffd83dbSDimitry Andric // This would remove the symbol from the map as well. 6755ffd83dbSDimitry Andric if (SymReaper.isDead(I.second)) 6765ffd83dbSDimitry Andric State = resolvePossiblyDestroyedMutex(State, I.first, &I.second); 6770b57cec5SDimitry Andric } 6785ffd83dbSDimitry Andric 6795ffd83dbSDimitry Andric for (auto I : State->get<LockMap>()) { 6805ffd83dbSDimitry Andric // Stop tracking dead mutex regions as well. 681fe6060f1SDimitry Andric if (!SymReaper.isLiveRegion(I.first)) { 6825ffd83dbSDimitry Andric State = State->remove<LockMap>(I.first); 683fe6060f1SDimitry Andric State = State->remove<DestroyRetVal>(I.first); 684fe6060f1SDimitry Andric } 6855ffd83dbSDimitry Andric } 6865ffd83dbSDimitry Andric 6875ffd83dbSDimitry Andric // TODO: We probably need to clean up the lock stack as well. 6885ffd83dbSDimitry Andric // It is tricky though: even if the mutex cannot be unlocked anymore, 6895ffd83dbSDimitry Andric // it can still participate in lock order reversal resolution. 6905ffd83dbSDimitry Andric 6910b57cec5SDimitry Andric C.addTransition(State); 6920b57cec5SDimitry Andric } 6930b57cec5SDimitry Andric 6945ffd83dbSDimitry Andric ProgramStateRef PthreadLockChecker::checkRegionChanges( 6955ffd83dbSDimitry Andric ProgramStateRef State, const InvalidatedSymbols *Symbols, 6965ffd83dbSDimitry Andric ArrayRef<const MemRegion *> ExplicitRegions, 6975ffd83dbSDimitry Andric ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx, 6985ffd83dbSDimitry Andric const CallEvent *Call) const { 6995ffd83dbSDimitry Andric 7005ffd83dbSDimitry Andric bool IsLibraryFunction = false; 7015ffd83dbSDimitry Andric if (Call && Call->isGlobalCFunction()) { 7025ffd83dbSDimitry Andric // Avoid invalidating mutex state when a known supported function is called. 7035ffd83dbSDimitry Andric if (PThreadCallbacks.lookup(*Call) || FuchsiaCallbacks.lookup(*Call) || 7045ffd83dbSDimitry Andric C11Callbacks.lookup(*Call)) 7055ffd83dbSDimitry Andric return State; 7065ffd83dbSDimitry Andric 7075ffd83dbSDimitry Andric if (Call->isInSystemHeader()) 7085ffd83dbSDimitry Andric IsLibraryFunction = true; 7095ffd83dbSDimitry Andric } 7105ffd83dbSDimitry Andric 7115ffd83dbSDimitry Andric for (auto R : Regions) { 7125ffd83dbSDimitry Andric // We assume that system library function wouldn't touch the mutex unless 7135ffd83dbSDimitry Andric // it takes the mutex explicitly as an argument. 7145ffd83dbSDimitry Andric // FIXME: This is a bit quadratic. 715349cc55cSDimitry Andric if (IsLibraryFunction && !llvm::is_contained(ExplicitRegions, R)) 7165ffd83dbSDimitry Andric continue; 7175ffd83dbSDimitry Andric 7185ffd83dbSDimitry Andric State = State->remove<LockMap>(R); 7195ffd83dbSDimitry Andric State = State->remove<DestroyRetVal>(R); 7205ffd83dbSDimitry Andric 7215ffd83dbSDimitry Andric // TODO: We need to invalidate the lock stack as well. This is tricky 7225ffd83dbSDimitry Andric // to implement correctly and efficiently though, because the effects 7235ffd83dbSDimitry Andric // of mutex escapes on lock order may be fairly varied. 7245ffd83dbSDimitry Andric } 7255ffd83dbSDimitry Andric 7265ffd83dbSDimitry Andric return State; 7275ffd83dbSDimitry Andric } 7285ffd83dbSDimitry Andric 7295ffd83dbSDimitry Andric void ento::registerPthreadLockBase(CheckerManager &mgr) { 7300b57cec5SDimitry Andric mgr.registerChecker<PthreadLockChecker>(); 7310b57cec5SDimitry Andric } 7320b57cec5SDimitry Andric 7335ffd83dbSDimitry Andric bool ento::shouldRegisterPthreadLockBase(const CheckerManager &mgr) { return true; } 7345ffd83dbSDimitry Andric 7355ffd83dbSDimitry Andric #define REGISTER_CHECKER(name) \ 7365ffd83dbSDimitry Andric void ento::register##name(CheckerManager &mgr) { \ 7375ffd83dbSDimitry Andric PthreadLockChecker *checker = mgr.getChecker<PthreadLockChecker>(); \ 7385ffd83dbSDimitry Andric checker->ChecksEnabled[PthreadLockChecker::CK_##name] = true; \ 7395ffd83dbSDimitry Andric checker->CheckNames[PthreadLockChecker::CK_##name] = \ 7405ffd83dbSDimitry Andric mgr.getCurrentCheckerName(); \ 7415ffd83dbSDimitry Andric } \ 7425ffd83dbSDimitry Andric \ 7435ffd83dbSDimitry Andric bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } 7445ffd83dbSDimitry Andric 7455ffd83dbSDimitry Andric REGISTER_CHECKER(PthreadLockChecker) 7465ffd83dbSDimitry Andric REGISTER_CHECKER(FuchsiaLockChecker) 7475ffd83dbSDimitry Andric REGISTER_CHECKER(C11LockChecker) 748