21 #include "llvm/ADT/ImmutableList.h"
23 using namespace clang;
29 enum Kind { Destroyed, Locked, Unlocked } K;
32 LockState(
Kind K) : K(K) {}
35 static LockState getLocked() {
return LockState(Locked); }
36 static LockState getUnlocked() {
return LockState(Unlocked); }
37 static LockState getDestroyed() {
return LockState(Destroyed); }
43 bool isLocked()
const {
return K == Locked; }
44 bool isUnlocked()
const {
return K == Unlocked; }
45 bool isDestroyed()
const {
return K == Destroyed; }
47 void Profile(llvm::FoldingSetNodeID &
ID)
const {
52 class PthreadLockChecker :
public Checker< check::PostStmt<CallExpr> > {
53 mutable std::unique_ptr<BugType> BT_doublelock;
54 mutable std::unique_ptr<BugType> BT_doubleunlock;
55 mutable std::unique_ptr<BugType> BT_destroylock;
56 mutable std::unique_ptr<BugType> BT_initlock;
57 mutable std::unique_ptr<BugType> BT_lor;
58 enum LockingSemantics {
67 bool isTryLock,
enum LockingSemantics semantics)
const;
81 void PthreadLockChecker::checkPostStmt(const
CallExpr *CE,
85 StringRef FName = C.getCalleeName(CE);
89 if (CE->getNumArgs() != 1 && CE->getNumArgs() != 2)
92 if (FName ==
"pthread_mutex_lock" ||
93 FName ==
"pthread_rwlock_rdlock" ||
94 FName ==
"pthread_rwlock_wrlock")
95 AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
96 false, PthreadSemantics);
97 else if (FName ==
"lck_mtx_lock" ||
98 FName ==
"lck_rw_lock_exclusive" ||
99 FName ==
"lck_rw_lock_shared")
100 AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
101 false, XNUSemantics);
102 else if (FName ==
"pthread_mutex_trylock" ||
103 FName ==
"pthread_rwlock_tryrdlock" ||
104 FName ==
"pthread_rwlock_trywrlock")
105 AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
106 true, PthreadSemantics);
107 else if (FName ==
"lck_mtx_try_lock" ||
108 FName ==
"lck_rw_try_lock_exclusive" ||
109 FName ==
"lck_rw_try_lock_shared")
110 AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
112 else if (FName ==
"pthread_mutex_unlock" ||
113 FName ==
"pthread_rwlock_unlock" ||
114 FName ==
"lck_mtx_unlock" ||
115 FName ==
"lck_rw_done")
116 ReleaseLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
117 else if (FName ==
"pthread_mutex_destroy" ||
118 FName ==
"lck_mtx_destroy")
119 DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
120 else if (FName ==
"pthread_mutex_init")
121 InitLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
125 SVal lock,
bool isTryLock,
126 enum LockingSemantics semantics)
const {
140 if (
const LockState *LState = state->get<LockMap>(lockR)) {
141 if (LState->isLocked()) {
143 BT_doublelock.reset(
new BugType(
this,
"Double locking",
148 auto report = llvm::make_unique<BugReport>(
149 *BT_doublelock,
"This lock has already been acquired", N);
150 report->addRange(CE->
getArg(0)->getSourceRange());
153 }
else if (LState->isDestroyed()) {
154 reportUseDestroyedBug(C, CE);
164 case PthreadSemantics:
165 std::tie(lockFail, lockSucc) = state->assume(retVal);
168 std::tie(lockSucc, lockFail) = state->assume(retVal);
171 llvm_unreachable(
"Unknown tryLock locking semantics");
173 assert(lockFail && lockSucc);
176 }
else if (semantics == PthreadSemantics) {
178 lockSucc = state->assume(retVal,
false);
183 assert((semantics == XNUSemantics) &&
"Unknown locking semantics");
188 lockSucc = lockSucc->add<LockSet>(lockR);
189 lockSucc = lockSucc->set<LockMap>(lockR, LockState::getLocked());
202 if (
const LockState *LState = state->get<LockMap>(lockR)) {
203 if (LState->isUnlocked()) {
204 if (!BT_doubleunlock)
205 BT_doubleunlock.reset(
new BugType(
this,
"Double unlocking",
210 auto Report = llvm::make_unique<BugReport>(
211 *BT_doubleunlock,
"This lock has already been unlocked", N);
212 Report->addRange(CE->
getArg(0)->getSourceRange());
215 }
else if (LState->isDestroyed()) {
216 reportUseDestroyedBug(C, CE);
221 LockSetTy LS = state->get<LockSet>();
226 const MemRegion *firstLockR = LS.getHead();
227 if (firstLockR != lockR) {
229 BT_lor.reset(
new BugType(
this,
"Lock order reversal",
"Lock checker"));
233 auto report = llvm::make_unique<BugReport>(
234 *BT_lor,
"This was not the most recently acquired lock. Possible "
235 "lock order reversal", N);
236 report->addRange(CE->
getArg(0)->getSourceRange());
241 state = state->set<LockSet>(LS.getTail());
244 state = state->set<LockMap>(lockR, LockState::getUnlocked());
257 const LockState *LState = State->get<LockMap>(LockR);
258 if (!LState || LState->isUnlocked()) {
259 State = State->set<LockMap>(LockR, LockState::getDestroyed());
266 if (LState->isLocked()) {
267 Message =
"This lock is still locked";
269 Message =
"This lock has already been destroyed";
273 BT_destroylock.reset(
new BugType(
this,
"Destroy invalid lock",
278 auto Report = llvm::make_unique<BugReport>(*BT_destroylock, Message, N);
279 Report->addRange(CE->
getArg(0)->getSourceRange());
292 const struct LockState *LState = State->get<LockMap>(LockR);
293 if (!LState || LState->isDestroyed()) {
294 State = State->set<LockMap>(LockR, LockState::getUnlocked());
301 if (LState->isLocked()) {
302 Message =
"This lock is still being held";
304 Message =
"This lock has already been initialized";
308 BT_initlock.reset(
new BugType(
this,
"Init invalid lock",
313 auto Report = llvm::make_unique<BugReport>(*BT_initlock, Message, N);
314 Report->addRange(CE->
getArg(0)->getSourceRange());
321 BT_destroylock.reset(
new BugType(
this,
"Use destroyed lock",
326 auto Report = llvm::make_unique<BugReport>(
327 *BT_destroylock,
"This lock has already been destroyed", N);
328 Report->addRange(CE->
getArg(0)->getSourceRange());
MemRegion - The root abstract class for all memory regions.
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
bool operator==(CanQual< T > x, CanQual< U > y)
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
bool isUnknownOrUndef() const
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
const ProgramStateRef & getState() const
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
CHECKER * registerChecker()
Used to register checkers.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx)
const MemRegion * getAsRegion() const
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
#define REGISTER_LIST_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable list of type NameTy, suitable for placement into the ProgramState.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
const LocationContext * getLocationContext() const