void PthreadLockChecker::printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const { LockMapTy LM = State->get<LockMap>(); if (!LM.isEmpty()) { Out << Sep << "Mutex states:" << NL; for (auto I : LM) { I.first->dumpToStream(Out); if (I.second.isLocked()) Out << ": locked"; else if (I.second.isUnlocked()) Out << ": unlocked"; else if (I.second.isDestroyed()) Out << ": destroyed"; else if (I.second.isUntouchedAndPossiblyDestroyed()) Out << ": not tracked, possibly destroyed"; else if (I.second.isUnlockedAndPossiblyDestroyed()) Out << ": unlocked, possibly destroyed"; Out << NL; } } LockSetTy LS = State->get<LockSet>(); if (!LS.isEmpty()) { Out << Sep << "Mutex lock order:" << NL; for (auto I: LS) { I->dumpToStream(Out); Out << NL; } } // TODO: Dump destroyed mutex symbols? }
void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) const { const MemRegion *lockR = lock.getAsRegion(); if (!lockR) return; ProgramStateRef state = C.getState(); if (const LockState *LState = state->get<LockMap>(lockR)) { if (LState->isUnlocked()) { if (!BT_doubleunlock) BT_doubleunlock.reset(new BugType(this, "Double unlocking", "Lock checker")); ExplodedNode *N = C.generateSink(); if (!N) return; BugReport *Report = new BugReport(*BT_doubleunlock, "This lock has already been unlocked", N); Report->addRange(CE->getArg(0)->getSourceRange()); C.emitReport(Report); return; } else if (LState->isDestroyed()) { reportUseDestroyedBug(C, CE); return; } } LockSetTy LS = state->get<LockSet>(); // FIXME: Better analysis requires IPA for wrappers. if (!LS.isEmpty()) { const MemRegion *firstLockR = LS.getHead(); if (firstLockR != lockR) { if (!BT_lor) BT_lor.reset(new BugType(this, "Lock order reversal", "Lock checker")); ExplodedNode *N = C.generateSink(); if (!N) return; BugReport *report = new BugReport(*BT_lor, "This was not the most recently " "acquired lock. Possible lock order " "reversal", N); report->addRange(CE->getArg(0)->getSourceRange()); C.emitReport(report); return; } // Record that the lock was released. state = state->set<LockSet>(LS.getTail()); } state = state->set<LockMap>(lockR, LockState::getUnlocked()); C.addTransition(state); }
void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) const { const MemRegion *lockR = lock.getAsRegion(); if (!lockR) return; ProgramStateRef state = C.getState(); LockSetTy LS = state->get<LockSet>(); // FIXME: Better analysis requires IPA for wrappers. // FIXME: check for double unlocks if (LS.isEmpty()) return; const MemRegion *firstLockR = LS.getHead(); if (firstLockR != lockR) { if (!BT_lor) BT_lor.reset(new BugType("Lock order reversal", "Lock checker")); ExplodedNode *N = C.generateSink(); if (!N) return; BugReport *report = new BugReport(*BT_lor, "This was not the most " "recently acquired lock. " "Possible lock order " "reversal", N); report->addRange(CE->getArg(0)->getSourceRange()); C.emitReport(report); return; } // Record that the lock was released. state = state->set<LockSet>(LS.getTail()); C.addTransition(state); }