ASDenysPetrov created this revision. ASDenysPetrov added reviewers: NoQ, vsavchenko, xazax.hun, dcoughlin. ASDenysPetrov added a project: clang. Herald added subscribers: cfe-commits, steakhal, martong, Charusso, dkrupp, donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, szepet, baloghadamsoftware. ASDenysPetrov requested review of this revision.
This checker is made above PthreadLockChecker and works the same. It is adapted for **std::mutex** primitive. Next I want to add support **std::recursive_mutex**. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D85984 Files: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp clang/test/Analysis/Checkers/CPlusPlus11LockChecker.cpp
Index: clang/test/Analysis/Checkers/CPlusPlus11LockChecker.cpp =================================================================== --- /dev/null +++ clang/test/Analysis/Checkers/CPlusPlus11LockChecker.cpp @@ -0,0 +1,119 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.CPlusPlus11Lock -verify %s + +namespace std { + +struct mutex { + void lock(); + bool try_lock(); + void unlock(); +}; + +struct recursive_mutex { + void lock(); + bool try_lock(); + void unlock(); +}; + +template <typename T> +struct guard_lock { + T &t; + guard_lock(T &m) : t(m) { + t.lock(); + } + ~guard_lock() { + t.unlock(); + } +}; +} // namespace std + +std::mutex m1; +std::mutex m2; +std::recursive_mutex rm1; +std::recursive_mutex rm2; + +// ok + +void ok1() { + m1.lock(); // no-warning +} + +void ok2() { + m1.unlock(); // no-warning +} + +void ok3() { + m1.lock(); // no-warning + m1.unlock(); // no-warning +} + +void ok4() { + m1.lock(); // no-warning + m1.unlock(); // no-warning + m1.lock(); // no-warning + m1.unlock(); // no-warning +} + +void ok5() { + m1.lock(); // no-warning + m1.unlock(); // no-warning + m2.lock(); // no-warning + m2.unlock(); // no-warning +} + +void ok6(void) { + m1.lock(); // no-warning + m2.lock(); // no-warning + m2.unlock(); // no-warning + m1.unlock(); // no-warning +} + +void ok7(void) { + if (m1.try_lock()) // no-warning + m1.unlock(); // no-warning +} + +void ok8(void) { + m1.unlock(); // no-warning + if (m1.try_lock()) // no-warning + m1.unlock(); // no-warning +} + +void ok9(void) { + if (!m1.try_lock()) // no-warning + m1.lock(); // no-warning + m1.unlock(); // no-warning +} + +void ok10() { + std::guard_lock<std::mutex> gl(m1); +} + +// bad + +void bad1() { + m1.lock(); // no-warning + m1.lock(); // expected-warning{{This lock has already been acquired}} +} + +void bad2() { + m1.lock(); // no-warning + m1.unlock(); // no-warning + m1.unlock(); // expected-warning {{This lock has already been unlocked}} +} + +void bad3() { + m1.lock(); // no-warning + m2.lock(); // no-warning + m1.unlock(); // expected-warning {{This was not the most recently acquired lock. Possible lock order reversal}} + m2.unlock(); // no-warning +} + +void bad5() { + while (true) + m1.unlock(); // expected-warning {{This lock has already been unlocked}} +} + +void bad6() { + while (true) + m1.lock(); // expected-warning{{This lock has already been acquired}} +} Index: clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp @@ -70,11 +70,17 @@ class PthreadLockChecker : public Checker<check::PostCall, check::DeadSymbols, check::RegionChanges> { public: - enum LockingSemantics { NotApplicable = 0, PthreadSemantics, XNUSemantics }; + enum LockingSemantics { + NotApplicable = 0, + PthreadSemantics, + XNUSemantics, + CPlusPlusSemantics, + }; enum CheckerKind { CK_PthreadLockChecker, CK_FuchsiaLockChecker, CK_C11LockChecker, + CK_CPlusPlus11LockChecker, CK_NumCheckKinds }; DefaultBool ChecksEnabled[CK_NumCheckKinds]; @@ -83,7 +89,7 @@ private: typedef void (PthreadLockChecker::*FnCheck)(const CallEvent &Call, CheckerContext &C, - CheckerKind checkkind) const; + CheckerKind CheckKind) const; CallDescriptionMap<FnCheck> PThreadCallbacks = { // Init. {{"pthread_mutex_init", 2}, &PthreadLockChecker::InitAnyLock}, @@ -164,49 +170,82 @@ {{"mtx_destroy", 1}, &PthreadLockChecker::DestroyPthreadLock}, }; + CallDescriptionMap<FnCheck> CPlusPlus11Callbacks = { + + // Acquire. + {{{"std", "mutex", "lock"}, 0, 0}, + &PthreadLockChecker::AcquireCPlusPlus11Lock}, + // TODO {{{"std", "recursive_mutex", "lock"}, 0, 0}, + // &PthreadLockChecker::AcquireCPlusPlus11RecursiveLock}, + + // Try. + {{{"std", "mutex", "try_lock"}, 0, 0}, + &PthreadLockChecker::TryCPlusPlus11Lock}, + // TODO {{{"std", "recursive_mutex", "try_lock"}, 0, 0}, + // &PthreadLockChecker::TryCPlusPlus11RecursiveLock}, + + // Release. + {{{"std", "mutex", "unlock"}, 0, 0}, + &PthreadLockChecker::ReleaseCPlusPlus11Lock}, + // TODO {{{"std", "recursive_mutex", "unlock"}, 0, 0}, + // &PthreadLockChecker::ReleaseCPlusPlus11Lock}, + }; + ProgramStateRef resolvePossiblyDestroyedMutex(ProgramStateRef state, const MemRegion *lockR, const SymbolRef *sym) const; void reportUseDestroyedBug(const CallEvent &Call, CheckerContext &C, - unsigned ArgNo, CheckerKind checkKind) const; + const Expr *MtxExpr, CheckerKind CheckKind) const; // Init. void InitAnyLock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkkind) const; + CheckerKind CheckKind) const; void InitLockAux(const CallEvent &Call, CheckerContext &C, unsigned ArgNo, - SVal Lock, CheckerKind checkkind) const; + SVal Lock, CheckerKind CheckKind) const; // Lock, Try-lock. void AcquirePthreadLock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkkind) const; + CheckerKind CheckKind) const; void AcquireXNULock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkkind) const; + CheckerKind CheckKind) const; + void AcquireCPlusPlus11Lock(const CallEvent &Call, CheckerContext &C, + CheckerKind CheckKind) const; + void AcquireCPlusPlus11RecursiveLock(const CallEvent &Call, CheckerContext &C, + CheckerKind CheckKind) const; void TryPthreadLock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkkind) const; + CheckerKind CheckKind) const; void TryXNULock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkkind) const; + CheckerKind CheckKind) const; void TryFuchsiaLock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkkind) const; + CheckerKind CheckKind) const; void TryC11Lock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkkind) const; - void AcquireLockAux(const CallEvent &Call, CheckerContext &C, unsigned ArgNo, - SVal lock, bool isTryLock, LockingSemantics semantics, - CheckerKind checkkind) const; + CheckerKind CheckKind) const; + void TryCPlusPlus11Lock(const CallEvent &Call, CheckerContext &C, + CheckerKind CheckKind) const; + void TryCPlusPlus11RecursiveLock(const CallEvent &Call, CheckerContext &C, + CheckerKind CheckKind) const; + void AcquireLockAux(const CallEvent &Call, CheckerContext &C, + const Expr *MtxExpr, SVal MtxVal, bool IsTryLock, + bool IsRecursive, LockingSemantics semantics, + CheckerKind CheckKind) const; // Release. void ReleaseAnyLock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkkind) const; - void ReleaseLockAux(const CallEvent &Call, CheckerContext &C, unsigned ArgNo, - SVal lock, CheckerKind checkkind) const; + CheckerKind CheckKind) const; + void ReleaseCPlusPlus11Lock(const CallEvent &Call, CheckerContext &C, + CheckerKind CheckKind) const; + void ReleaseLockAux(const CallEvent &Call, CheckerContext &C, + const Expr *MtxExpr, SVal MtxVal, + LockingSemantics semantics, CheckerKind CheckKind) const; // Destroy. void DestroyPthreadLock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkkind) const; + CheckerKind CheckKind) const; void DestroyXNULock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkkind) const; + CheckerKind CheckKind) const; void DestroyLockAux(const CallEvent &Call, CheckerContext &C, unsigned ArgNo, SVal Lock, LockingSemantics semantics, - CheckerKind checkkind) const; + CheckerKind CheckKind) const; public: void checkPostCall(const CallEvent &Call, CheckerContext &C) const; @@ -226,18 +265,18 @@ mutable std::unique_ptr<BugType> BT_initlock[CK_NumCheckKinds]; mutable std::unique_ptr<BugType> BT_lor[CK_NumCheckKinds]; - void initBugType(CheckerKind checkKind) const { - if (BT_doublelock[checkKind]) + void initBugType(CheckerKind CheckKind) const { + if (BT_doublelock[CheckKind]) return; - BT_doublelock[checkKind].reset( - new BugType{CheckNames[checkKind], "Double locking", "Lock checker"}); - BT_doubleunlock[checkKind].reset( - new BugType{CheckNames[checkKind], "Double unlocking", "Lock checker"}); - BT_destroylock[checkKind].reset(new BugType{ - CheckNames[checkKind], "Use destroyed lock", "Lock checker"}); - BT_initlock[checkKind].reset(new BugType{ - CheckNames[checkKind], "Init invalid lock", "Lock checker"}); - BT_lor[checkKind].reset(new BugType{CheckNames[checkKind], + BT_doublelock[CheckKind].reset( + new BugType{CheckNames[CheckKind], "Double locking", "Lock checker"}); + BT_doubleunlock[CheckKind].reset( + new BugType{CheckNames[CheckKind], "Double unlocking", "Lock checker"}); + BT_destroylock[CheckKind].reset(new BugType{ + CheckNames[CheckKind], "Use destroyed lock", "Lock checker"}); + BT_initlock[CheckKind].reset(new BugType{ + CheckNames[CheckKind], "Init invalid lock", "Lock checker"}); + BT_lor[CheckKind].reset(new BugType{CheckNames[CheckKind], "Lock order reversal", "Lock checker"}); } }; @@ -260,7 +299,7 @@ // with exactly one identifier? // FIXME: Try to handle cases when the implementation was inlined rather // than just giving up. - if (!Call.isGlobalCFunction() || C.wasInlined) + if (C.wasInlined) return; if (const FnCheck *Callback = PThreadCallbacks.lookup(Call)) @@ -269,6 +308,8 @@ (this->**Callback)(Call, C, CK_FuchsiaLockChecker); else if (const FnCheck *Callback = C11Callbacks.lookup(Call)) (this->**Callback)(Call, C, CK_C11LockChecker); + else if (const FnCheck *Callback = CPlusPlus11Callbacks.lookup(Call)) + (this->**Callback)(Call, C, CK_CPlusPlus11LockChecker); } // When a lock is destroyed, in some semantics(like PthreadSemantics) we are not @@ -341,53 +382,92 @@ void PthreadLockChecker::AcquirePthreadLock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkKind) const { - AcquireLockAux(Call, C, 0, Call.getArgSVal(0), false, PthreadSemantics, - checkKind); + CheckerKind CheckKind) const { + AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), false, false, + PthreadSemantics, CheckKind); } void PthreadLockChecker::AcquireXNULock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkKind) const { - AcquireLockAux(Call, C, 0, Call.getArgSVal(0), false, XNUSemantics, - checkKind); + CheckerKind CheckKind) const { + AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), false, false, + XNUSemantics, CheckKind); +} + +void PthreadLockChecker::AcquireCPlusPlus11Lock(const CallEvent &Call, + CheckerContext &C, + CheckerKind CheckKind) const { + auto MemberCall = cast<CXXMemberCall>(&Call); + auto ThisExpr = MemberCall->getCXXThisExpr(); + auto ThisVal = MemberCall->getCXXThisVal(); + AcquireLockAux(Call, C, ThisExpr, ThisVal, false, false, CPlusPlusSemantics, + CheckKind); +} + +void PthreadLockChecker::AcquireCPlusPlus11RecursiveLock( + const CallEvent &Call, CheckerContext &C, CheckerKind CheckKind) const { + auto MemberCall = cast<CXXMemberCall>(&Call); + auto ThisExpr = MemberCall->getCXXThisExpr(); + auto ThisVal = MemberCall->getCXXThisVal(); + AcquireLockAux(Call, C, ThisExpr, ThisVal, false, true, CPlusPlusSemantics, + CheckKind); } void PthreadLockChecker::TryPthreadLock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkKind) const { - AcquireLockAux(Call, C, 0, Call.getArgSVal(0), true, PthreadSemantics, - checkKind); + CheckerKind CheckKind) const { + AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), true, false, + PthreadSemantics, CheckKind); } void PthreadLockChecker::TryXNULock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkKind) const { - AcquireLockAux(Call, C, 0, Call.getArgSVal(0), true, PthreadSemantics, - checkKind); + CheckerKind CheckKind) const { + AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), true, false, + PthreadSemantics, CheckKind); } void PthreadLockChecker::TryFuchsiaLock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkKind) const { - AcquireLockAux(Call, C, 0, Call.getArgSVal(0), true, PthreadSemantics, - checkKind); + CheckerKind CheckKind) const { + AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), true, false, + PthreadSemantics, CheckKind); } void PthreadLockChecker::TryC11Lock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkKind) const { - AcquireLockAux(Call, C, 0, Call.getArgSVal(0), true, PthreadSemantics, - checkKind); + CheckerKind CheckKind) const { + AcquireLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), true, false, + PthreadSemantics, CheckKind); +} + +void PthreadLockChecker::TryCPlusPlus11Lock(const CallEvent &Call, + CheckerContext &C, + CheckerKind CheckKind) const { + auto MemberCall = cast<CXXMemberCall>(&Call); + auto ThisExpr = MemberCall->getCXXThisExpr(); + auto ThisVal = MemberCall->getCXXThisVal(); + AcquireLockAux(Call, C, ThisExpr, ThisVal, true, false, CPlusPlusSemantics, + CheckKind); +} + +void PthreadLockChecker::TryCPlusPlus11RecursiveLock( + const CallEvent &Call, CheckerContext &C, CheckerKind CheckKind) const { + auto MemberCall = cast<CXXMemberCall>(&Call); + auto ThisExpr = MemberCall->getCXXThisExpr(); + auto ThisVal = MemberCall->getCXXThisVal(); + AcquireLockAux(Call, C, ThisExpr, ThisVal, true, true, CPlusPlusSemantics, + CheckKind); } void PthreadLockChecker::AcquireLockAux(const CallEvent &Call, - CheckerContext &C, unsigned ArgNo, - SVal lock, bool isTryLock, - enum LockingSemantics semantics, - CheckerKind checkKind) const { - if (!ChecksEnabled[checkKind]) + CheckerContext &C, const Expr *MtxExpr, + SVal MtxVal, bool IsTryLock, + bool IsRecursive, + LockingSemantics semantics, + CheckerKind CheckKind) const { + if (!ChecksEnabled[CheckKind]) return; - const MemRegion *lockR = lock.getAsRegion(); + const MemRegion *lockR = MtxVal.getAsRegion(); if (!lockR) return; @@ -397,24 +477,24 @@ state = resolvePossiblyDestroyedMutex(state, lockR, sym); if (const LockState *LState = state->get<LockMap>(lockR)) { - if (LState->isLocked()) { + if (LState->isLocked() && !IsRecursive) { ExplodedNode *N = C.generateErrorNode(); if (!N) return; - initBugType(checkKind); + initBugType(CheckKind); auto report = std::make_unique<PathSensitiveBugReport>( - *BT_doublelock[checkKind], "This lock has already been acquired", N); - report->addRange(Call.getArgExpr(ArgNo)->getSourceRange()); + *BT_doublelock[CheckKind], "This lock has already been acquired", N); + report->addRange(MtxExpr->getSourceRange()); C.emitReport(std::move(report)); return; } else if (LState->isDestroyed()) { - reportUseDestroyedBug(Call, C, ArgNo, checkKind); + reportUseDestroyedBug(Call, C, MtxExpr, CheckKind); return; } } ProgramStateRef lockSucc = state; - if (isTryLock) { + if (IsTryLock) { // Bifurcate the state, and allow a mode where the lock acquisition fails. SVal RetVal = Call.getReturnValue(); if (auto DefinedRetVal = RetVal.getAs<DefinedSVal>()) { @@ -423,6 +503,7 @@ case PthreadSemantics: std::tie(lockFail, lockSucc) = state->assume(*DefinedRetVal); break; + case CPlusPlusSemantics: case XNUSemantics: std::tie(lockSucc, lockFail) = state->assume(*DefinedRetVal); break; @@ -445,9 +526,11 @@ } // We might want to handle the case when the mutex lock function was inlined // and returned an Unknown or Undefined value. - } else { + } else if (semantics == XNUSemantics) { // XNU locking semantics return void on non-try locks - assert((semantics == XNUSemantics) && "Unknown locking semantics"); + lockSucc = state; + } else { + assert((semantics == CPlusPlusSemantics) && "Unknown locking semantics"); lockSucc = state; } @@ -459,18 +542,28 @@ void PthreadLockChecker::ReleaseAnyLock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkKind) const { - ReleaseLockAux(Call, C, 0, Call.getArgSVal(0), checkKind); + CheckerKind CheckKind) const { + ReleaseLockAux(Call, C, Call.getArgExpr(0), Call.getArgSVal(0), NotApplicable, + CheckKind); +} + +void PthreadLockChecker::ReleaseCPlusPlus11Lock(const CallEvent &Call, + CheckerContext &C, + CheckerKind CheckKind) const { + auto MemberCall = cast<CXXMemberCall>(&Call); + auto ThisExpr = MemberCall->getCXXThisExpr(); + auto ThisVal = MemberCall->getCXXThisVal(); + ReleaseLockAux(Call, C, ThisExpr, ThisVal, CPlusPlusSemantics, CheckKind); } void PthreadLockChecker::ReleaseLockAux(const CallEvent &Call, - CheckerContext &C, unsigned ArgNo, - SVal lock, - CheckerKind checkKind) const { - if (!ChecksEnabled[checkKind]) + CheckerContext &C, const Expr *MtxExpr, + SVal MtxVal, LockingSemantics semantics, + CheckerKind CheckKind) const { + if (!ChecksEnabled[CheckKind]) return; - const MemRegion *lockR = lock.getAsRegion(); + const MemRegion *lockR = MtxVal.getAsRegion(); if (!lockR) return; @@ -484,15 +577,15 @@ ExplodedNode *N = C.generateErrorNode(); if (!N) return; - initBugType(checkKind); + initBugType(CheckKind); auto Report = std::make_unique<PathSensitiveBugReport>( - *BT_doubleunlock[checkKind], "This lock has already been unlocked", + *BT_doubleunlock[CheckKind], "This lock has already been unlocked", N); - Report->addRange(Call.getArgExpr(ArgNo)->getSourceRange()); + Report->addRange(MtxExpr->getSourceRange()); C.emitReport(std::move(Report)); return; } else if (LState->isDestroyed()) { - reportUseDestroyedBug(Call, C, ArgNo, checkKind); + reportUseDestroyedBug(Call, C, MtxExpr, CheckKind); return; } } @@ -505,13 +598,13 @@ ExplodedNode *N = C.generateErrorNode(); if (!N) return; - initBugType(checkKind); + initBugType(CheckKind); auto report = std::make_unique<PathSensitiveBugReport>( - *BT_lor[checkKind], + *BT_lor[CheckKind], "This was not the most recently acquired lock. Possible " "lock order reversal", N); - report->addRange(Call.getArgExpr(ArgNo)->getSourceRange()); + report->addRange(MtxExpr->getSourceRange()); C.emitReport(std::move(report)); return; } @@ -525,22 +618,21 @@ void PthreadLockChecker::DestroyPthreadLock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkKind) const { - DestroyLockAux(Call, C, 0, Call.getArgSVal(0), PthreadSemantics, checkKind); + CheckerKind CheckKind) const { + DestroyLockAux(Call, C, 0, Call.getArgSVal(0), PthreadSemantics, CheckKind); } void PthreadLockChecker::DestroyXNULock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkKind) const { - DestroyLockAux(Call, C, 0, Call.getArgSVal(0), XNUSemantics, checkKind); + CheckerKind CheckKind) const { + DestroyLockAux(Call, C, 0, Call.getArgSVal(0), XNUSemantics, CheckKind); } void PthreadLockChecker::DestroyLockAux(const CallEvent &Call, CheckerContext &C, unsigned ArgNo, - SVal Lock, - enum LockingSemantics semantics, - CheckerKind checkKind) const { - if (!ChecksEnabled[checkKind]) + SVal Lock, LockingSemantics semantics, + CheckerKind CheckKind) const { + if (!ChecksEnabled[CheckKind]) return; const MemRegion *LockR = Lock.getAsRegion(); @@ -592,22 +684,22 @@ ExplodedNode *N = C.generateErrorNode(); if (!N) return; - initBugType(checkKind); + initBugType(CheckKind); auto Report = std::make_unique<PathSensitiveBugReport>( - *BT_destroylock[checkKind], Message, N); + *BT_destroylock[CheckKind], Message, N); Report->addRange(Call.getArgExpr(ArgNo)->getSourceRange()); C.emitReport(std::move(Report)); } void PthreadLockChecker::InitAnyLock(const CallEvent &Call, CheckerContext &C, - CheckerKind checkKind) const { - InitLockAux(Call, C, 0, Call.getArgSVal(0), checkKind); + CheckerKind CheckKind) const { + InitLockAux(Call, C, 0, Call.getArgSVal(0), CheckKind); } void PthreadLockChecker::InitLockAux(const CallEvent &Call, CheckerContext &C, unsigned ArgNo, SVal Lock, - CheckerKind checkKind) const { - if (!ChecksEnabled[checkKind]) + CheckerKind CheckKind) const { + if (!ChecksEnabled[CheckKind]) return; const MemRegion *LockR = Lock.getAsRegion(); @@ -638,24 +730,24 @@ ExplodedNode *N = C.generateErrorNode(); if (!N) return; - initBugType(checkKind); + initBugType(CheckKind); auto Report = std::make_unique<PathSensitiveBugReport>( - *BT_initlock[checkKind], Message, N); + *BT_initlock[CheckKind], Message, N); Report->addRange(Call.getArgExpr(ArgNo)->getSourceRange()); C.emitReport(std::move(Report)); } void PthreadLockChecker::reportUseDestroyedBug(const CallEvent &Call, CheckerContext &C, - unsigned ArgNo, - CheckerKind checkKind) const { + const Expr *MtxExpr, + CheckerKind CheckKind) const { ExplodedNode *N = C.generateErrorNode(); if (!N) return; - initBugType(checkKind); + initBugType(CheckKind); auto Report = std::make_unique<PathSensitiveBugReport>( - *BT_destroylock[checkKind], "This lock has already been destroyed", N); - Report->addRange(Call.getArgExpr(ArgNo)->getSourceRange()); + *BT_destroylock[CheckKind], "This lock has already been destroyed", N); + Report->addRange(MtxExpr->getSourceRange()); C.emitReport(std::move(Report)); } @@ -691,10 +783,10 @@ const CallEvent *Call) const { bool IsLibraryFunction = false; - if (Call && Call->isGlobalCFunction()) { + if (Call) { // Avoid invalidating mutex state when a known supported function is called. if (PThreadCallbacks.lookup(*Call) || FuchsiaCallbacks.lookup(*Call) || - C11Callbacks.lookup(*Call)) + C11Callbacks.lookup(*Call) || CPlusPlus11Callbacks.lookup(*Call)) return State; if (Call->isInSystemHeader()) @@ -740,3 +832,4 @@ REGISTER_CHECKER(PthreadLockChecker) REGISTER_CHECKER(FuchsiaLockChecker) REGISTER_CHECKER(C11LockChecker) +REGISTER_CHECKER(CPlusPlus11LockChecker) Index: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -749,6 +749,11 @@ Dependencies<[SmartPtrModeling]>, Documentation<HasAlphaDocumentation>; +def CPlusPlus11LockChecker : Checker<"CPlusPlus11Lock">, + HelpText<"Simple C++11 lock -> unlock checker">, + Dependencies<[PthreadLockBase]>, + Documentation<HasAlphaDocumentation>; + } // end: "alpha.cplusplus"
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits