[analyzer] Lock checker: Allow pthread_mutex_init to reinitialize a destroyed lock.
Patch by Daniel Fahlgren! llvm-svn: 205276
This commit is contained in:
parent
7fcaa14a82
commit
3a176ed16d
|
@ -53,6 +53,7 @@ class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
|
|||
mutable std::unique_ptr<BugType> BT_doublelock;
|
||||
mutable std::unique_ptr<BugType> BT_doubleunlock;
|
||||
mutable std::unique_ptr<BugType> BT_destroylock;
|
||||
mutable std::unique_ptr<BugType> BT_initlock;
|
||||
mutable std::unique_ptr<BugType> BT_lor;
|
||||
enum LockingSemantics {
|
||||
NotApplicable = 0,
|
||||
|
@ -67,6 +68,7 @@ public:
|
|||
|
||||
void ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) const;
|
||||
void DestroyLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const;
|
||||
void InitLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const;
|
||||
void reportUseDestroyedBug(CheckerContext &C, const CallExpr *CE) const;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
@ -115,6 +117,8 @@ void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
|
|||
else if (FName == "pthread_mutex_destroy" ||
|
||||
FName == "lck_mtx_destroy")
|
||||
DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
|
||||
else if (FName == "pthread_mutex_init")
|
||||
InitLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
|
||||
}
|
||||
|
||||
void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
|
||||
|
@ -280,6 +284,41 @@ void PthreadLockChecker::DestroyLock(CheckerContext &C, const CallExpr *CE,
|
|||
C.emitReport(Report);
|
||||
}
|
||||
|
||||
void PthreadLockChecker::InitLock(CheckerContext &C, const CallExpr *CE,
|
||||
SVal Lock) const {
|
||||
|
||||
const MemRegion *LockR = Lock.getAsRegion();
|
||||
if (!LockR)
|
||||
return;
|
||||
|
||||
ProgramStateRef State = C.getState();
|
||||
|
||||
const struct LockState *LState = State->get<LockMap>(LockR);
|
||||
if (!LState || LState->isDestroyed()) {
|
||||
State = State->set<LockMap>(LockR, LockState::getUnlocked());
|
||||
C.addTransition(State);
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef Message;
|
||||
|
||||
if (LState->isLocked()) {
|
||||
Message = "This lock is still being held";
|
||||
} else {
|
||||
Message = "This lock has already been initialized";
|
||||
}
|
||||
|
||||
if (!BT_initlock)
|
||||
BT_initlock.reset(new BugType(this, "Init invalid lock",
|
||||
"Lock checker"));
|
||||
ExplodedNode *N = C.generateSink();
|
||||
if (!N)
|
||||
return;
|
||||
BugReport *Report = new BugReport(*BT_initlock, Message, N);
|
||||
Report->addRange(CE->getArg(0)->getSourceRange());
|
||||
C.emitReport(Report);
|
||||
}
|
||||
|
||||
void PthreadLockChecker::reportUseDestroyedBug(CheckerContext &C,
|
||||
const CallExpr *CE) const {
|
||||
if (!BT_destroylock)
|
||||
|
|
|
@ -6,6 +6,10 @@ typedef struct {
|
|||
void *foo;
|
||||
} pthread_mutex_t;
|
||||
|
||||
typedef struct {
|
||||
void *foo;
|
||||
} pthread_mutexattr_t;
|
||||
|
||||
typedef struct {
|
||||
void *foo;
|
||||
} lck_grp_t;
|
||||
|
@ -16,6 +20,7 @@ extern int pthread_mutex_lock(pthread_mutex_t *);
|
|||
extern int pthread_mutex_unlock(pthread_mutex_t *);
|
||||
extern int pthread_mutex_trylock(pthread_mutex_t *);
|
||||
extern int pthread_mutex_destroy(pthread_mutex_t *);
|
||||
extern int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
|
||||
extern int lck_mtx_lock(lck_mtx_t *);
|
||||
extern int lck_mtx_unlock(lck_mtx_t *);
|
||||
extern int lck_mtx_try_lock(lck_mtx_t *);
|
||||
|
@ -25,6 +30,8 @@ pthread_mutex_t mtx1, mtx2;
|
|||
lck_mtx_t lck1, lck2;
|
||||
lck_grp_t grp1;
|
||||
|
||||
#define NULL 0
|
||||
|
||||
void
|
||||
ok1(void)
|
||||
{
|
||||
|
@ -137,6 +144,45 @@ ok15(void)
|
|||
pthread_mutex_destroy(&mtx1); // no-warning
|
||||
}
|
||||
|
||||
void
|
||||
ok16(void)
|
||||
{
|
||||
pthread_mutex_init(&mtx1, NULL); // no-warning
|
||||
}
|
||||
|
||||
void
|
||||
ok17(void)
|
||||
{
|
||||
pthread_mutex_init(&mtx1, NULL); // no-warning
|
||||
pthread_mutex_init(&mtx2, NULL); // no-warning
|
||||
}
|
||||
|
||||
void
|
||||
ok18(void)
|
||||
{
|
||||
pthread_mutex_destroy(&mtx1); // no-warning
|
||||
pthread_mutex_init(&mtx1, NULL); // no-warning
|
||||
}
|
||||
|
||||
void
|
||||
ok19(void)
|
||||
{
|
||||
pthread_mutex_destroy(&mtx1); // no-warning
|
||||
pthread_mutex_init(&mtx1, NULL); // no-warning
|
||||
pthread_mutex_destroy(&mtx2); // no-warning
|
||||
pthread_mutex_init(&mtx2, NULL); // no-warning
|
||||
}
|
||||
|
||||
void
|
||||
ok20(void)
|
||||
{
|
||||
pthread_mutex_unlock(&mtx1); // no-warning
|
||||
pthread_mutex_destroy(&mtx1); // no-warning
|
||||
pthread_mutex_init(&mtx1, NULL); // no-warning
|
||||
pthread_mutex_destroy(&mtx1); // no-warning
|
||||
pthread_mutex_init(&mtx1, NULL); // no-warning
|
||||
}
|
||||
|
||||
void
|
||||
bad1(void)
|
||||
{
|
||||
|
@ -331,3 +377,24 @@ bad23(void)
|
|||
lck_mtx_lock(&mtx1); // no-warning
|
||||
lck_mtx_destroy(&mtx1, &grp1); // expected-warning{{This lock is still locked}}
|
||||
}
|
||||
|
||||
void
|
||||
bad24(void)
|
||||
{
|
||||
pthread_mutex_init(&mtx1, NULL); // no-warning
|
||||
pthread_mutex_init(&mtx1, NULL); // expected-warning{{This lock has already been initialized}}
|
||||
}
|
||||
|
||||
void
|
||||
bad25(void)
|
||||
{
|
||||
pthread_mutex_lock(&mtx1); // no-warning
|
||||
pthread_mutex_init(&mtx1, NULL); // expected-warning{{This lock is still being held}}
|
||||
}
|
||||
|
||||
void
|
||||
bad26(void)
|
||||
{
|
||||
pthread_mutex_unlock(&mtx1); // no-warning
|
||||
pthread_mutex_init(&mtx1, NULL); // expected-warning{{This lock has already been initialized}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue