Index: lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp +++ lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp @@ -25,7 +25,7 @@ namespace { struct LockState { - enum Kind { Destroyed, Locked, Unlocked } K; + enum Kind { Destroyed, Locked, Unlocked, SchrodingerLocked, SchrodingerUnlocked } K; private: LockState(Kind K) : K(K) {} @@ -34,6 +34,8 @@ static LockState getLocked() { return LockState(Locked); } static LockState getUnlocked() { return LockState(Unlocked); } static LockState getDestroyed() { return LockState(Destroyed); } + static LockState getSchrodingerLocked() { return LockState(SchrodingerLocked); } + static LockState getSchrodingerUnlocked() { return LockState(SchrodingerUnlocked); } bool operator==(const LockState &X) const { return K == X.K; @@ -42,13 +44,15 @@ bool isLocked() const { return K == Locked; } bool isUnlocked() const { return K == Unlocked; } bool isDestroyed() const { return K == Destroyed; } + bool isSchrodingerLocked() const { return K == SchrodingerLocked; } + bool isSchrodingerUnlocked() const { return K == SchrodingerUnlocked; } void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); } }; -class PthreadLockChecker : public Checker< check::PostStmt > { +class PthreadLockChecker : public Checker< check::PostStmt, check::DeadSymbols > { mutable std::unique_ptr BT_doublelock; mutable std::unique_ptr BT_doubleunlock; mutable std::unique_ptr BT_destroylock; @@ -61,6 +65,7 @@ }; public: void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; + void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; void AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock, bool isTryLock, enum LockingSemantics semantics) const; @@ -69,6 +74,7 @@ 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; + ProgramStateRef setAppropriateLockState(ProgramStateRef state, const MemRegion* lockR) const; }; } // end anonymous namespace @@ -76,6 +82,7 @@ REGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *) REGISTER_MAP_WITH_PROGRAMSTATE(LockMap, const MemRegion *, LockState) +REGISTER_MAP_WITH_PROGRAMSTATE(DestroyRetVal, const MemRegion *, SymbolRef) void PthreadLockChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { @@ -120,16 +127,40 @@ InitLock(C, CE, state->getSVal(CE->getArg(0), LCtx)); } +ProgramStateRef PthreadLockChecker::setAppropriateLockState(ProgramStateRef state, const MemRegion* lockR) const { + const SymbolRef* sym = state->get(lockR); + if(sym){ + const LockState* lstate = state->get(lockR); + if(lstate){ + ConstraintManager &CMgr = state->getConstraintManager(); + ConditionTruthVal retZero = CMgr.isNull(state, *sym); + if(retZero.isConstrainedFalse()){ + if(lstate->isSchrodingerLocked()) + state = state->set(lockR, LockState::getLocked()); + else if(lstate->isSchrodingerUnlocked()) + state = state->set(lockR, LockState::getUnlocked()); + } + else{ + if(!lstate || lstate->isSchrodingerLocked() || lstate->isSchrodingerUnlocked()) + state = state->set(lockR, LockState::getDestroyed()); + } + } + } + return state; +} + void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock, bool isTryLock, enum LockingSemantics semantics) const { const MemRegion *lockR = lock.getAsRegion(); if (!lockR) - return; + return; ProgramStateRef state = C.getState(); + state = setAppropriateLockState(state, lockR); + SVal X = state->getSVal(CE, C.getLocationContext()); if (X.isUnknownOrUndef()) return; @@ -198,6 +229,8 @@ ProgramStateRef state = C.getState(); + state = setAppropriateLockState(state, lockR); + if (const LockState *LState = state->get(lockR)) { if (LState->isUnlocked()) { if (!BT_doubleunlock) @@ -253,9 +286,32 @@ ProgramStateRef State = C.getState(); + State = setAppropriateLockState(State, LockR); + + // CHECK THIS const LockState *LState = State->get(LockR); - if (!LState || LState->isUnlocked()) { - State = State->set(LockR, LockState::getDestroyed()); + if(!LState){ + SVal X = State->getSVal(CE, C.getLocationContext()); + if (X.isUnknownOrUndef()){ + return; + } + + DefinedSVal retVal = X.castAs(); + retVal.dump(); + SymbolRef sym = retVal.getAsSymbol(); + State = State->set(LockR, sym); + C.addTransition(State); + return; + } + if (LState->isUnlocked()) { + SVal X = State->getSVal(CE, C.getLocationContext()); + if (X.isUnknownOrUndef()) + return; + + DefinedSVal retVal = X.castAs(); + SymbolRef sym = retVal.getAsSymbol(); + State = State->set(LockR, sym); + State = State->set(LockR, LockState::getSchrodingerUnlocked()); C.addTransition(State); return; } @@ -327,6 +383,37 @@ Report->addRange(CE->getArg(0)->getSourceRange()); C.emitReport(std::move(Report)); } +void PthreadLockChecker::checkDeadSymbols(SymbolReaper &SymReaper, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); + ConstraintManager &CMgr = State->getConstraintManager(); + + DestroyRetValTy TrackedSymbols = State->get(); + for (DestroyRetValTy::iterator I = TrackedSymbols.begin(), + E = TrackedSymbols.end(); I != E; ++I) { + SymbolRef Sym = I->second; + const MemRegion* lockR = I->first; + bool IsSymDead = SymReaper.isDead(Sym); + const LockState* LState = State->get(lockR); + // Remove the dead symbol from the return value symbols map. + if (IsSymDead){ + ConditionTruthVal retZero = CMgr.isNull(State, Sym); + if(retZero.isConstrainedFalse()){ + if(LState && LState->isSchrodingerLocked()) + State = State->set(lockR, LockState::getLocked()); + else if(LState && LState->isSchrodingerUnlocked()) + State = State->set(lockR, LockState::getUnlocked()); + } + else{ + // IS THIS CORRECT? + if(!LState || LState->isSchrodingerUnlocked() || LState->isSchrodingerLocked()) + State = State->set(lockR, LockState::getDestroyed()); + } + State = State->remove(lockR); + } + } + C.addTransition(State); +} void ento::registerPthreadLockChecker(CheckerManager &mgr) { mgr.registerChecker();