diff --git a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp index 76ae02731a3d3c6dbbf8fd10f5fe9f46120b96da..1ede3a2a512637c2052f364b35db797fd512cfa4 100644 --- a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp @@ -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) diff --git a/test/Analysis/pthreadlock.c b/test/Analysis/pthreadlock.c index 6a75a6e480e491dacffababfffa83fc732993aa1..2a59e0ffe98acd3d3d09da248b2dc9dff1ca5539 100644 --- a/test/Analysis/pthreadlock.c +++ b/test/Analysis/pthreadlock.c @@ -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}} +}