diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Analysis/LiveVariables.cpp | 12 | ||||
-rw-r--r-- | lib/Analysis/UninitializedValues.cpp | 2 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp | 66 |
3 files changed, 71 insertions, 9 deletions
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp index 47b2e3d604..303dc0f604 100644 --- a/lib/Analysis/LiveVariables.cpp +++ b/lib/Analysis/LiveVariables.cpp @@ -104,8 +104,9 @@ namespace { class TransferFuncs : public CFGRecStmtVisitor<TransferFuncs>{ LiveVariables::AnalysisDataTy& AD; LiveVariables::ValTy LiveState; + const CFGBlock *currentBlock; public: - TransferFuncs(LiveVariables::AnalysisDataTy& ad) : AD(ad) {} + TransferFuncs(LiveVariables::AnalysisDataTy& ad) : AD(ad), currentBlock(0) {} LiveVariables::ValTy& getVal() { return LiveState; } CFG& getCFG() { return AD.getCFG(); } @@ -128,7 +129,10 @@ public: void SetTopValue(LiveVariables::ValTy& V) { V = AD.AlwaysLive; } - + + void setCurrentBlock(const CFGBlock *block) { + currentBlock = block; + } }; void TransferFuncs::Visit(Stmt *S) { @@ -136,7 +140,7 @@ void TransferFuncs::Visit(Stmt *S) { if (S == getCurrentBlkStmt()) { if (AD.Observer) - AD.Observer->ObserveStmt(S,AD,LiveState); + AD.Observer->ObserveStmt(S, currentBlock, AD, LiveState); if (getCFG().isBlkExpr(S)) LiveState(S, AD) = Dead; @@ -146,7 +150,7 @@ void TransferFuncs::Visit(Stmt *S) { else if (!getCFG().isBlkExpr(S)) { if (AD.Observer) - AD.Observer->ObserveStmt(S,AD,LiveState); + AD.Observer->ObserveStmt(S, currentBlock, AD, LiveState); StmtVisitor<TransferFuncs,void>::Visit(S); diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp index 5e8331f282..73bce8b3b7 100644 --- a/lib/Analysis/UninitializedValues.cpp +++ b/lib/Analysis/UninitializedValues.cpp @@ -79,6 +79,8 @@ public: bool BlockStmt_VisitExpr(Expr* E); void VisitTerminator(CFGBlock* B) { } + + void setCurrentBlock(const CFGBlock *block) {} }; static const bool Initialized = false; diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index e2b3d81931..442e1b3af7 100644 --- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -28,26 +28,80 @@ using namespace ento; namespace { +// FIXME: Eventually migrate into its own file, and have it managed by +// AnalysisManager. +class ReachableCode { + const CFG &cfg; + llvm::BitVector reachable; +public: + ReachableCode(const CFG &cfg) + : cfg(cfg), reachable(cfg.getNumBlockIDs(), false) {} + + void computeReachableBlocks(); + + bool isReachable(const CFGBlock *block) const { + return reachable[block->getBlockID()]; + } +}; +} + +void ReachableCode::computeReachableBlocks() { + if (!cfg.getNumBlockIDs()) + return; + + llvm::SmallVector<const CFGBlock*, 10> worklist; + worklist.push_back(&cfg.getEntry()); + + while (!worklist.empty()) { + const CFGBlock *block = worklist.back(); + worklist.pop_back(); + llvm::BitVector::reference isReachable = reachable[block->getBlockID()]; + if (isReachable) + continue; + isReachable = true; + for (CFGBlock::const_succ_iterator i = block->succ_begin(), + e = block->succ_end(); i != e; ++i) + if (const CFGBlock *succ = *i) + worklist.push_back(succ); + } +} + +namespace { class DeadStoreObs : public LiveVariables::ObserverTy { + const CFG &cfg; ASTContext &Ctx; BugReporter& BR; ParentMap& Parents; llvm::SmallPtrSet<VarDecl*, 20> Escaped; + llvm::OwningPtr<ReachableCode> reachableCode; + const CFGBlock *currentBlock; enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit }; public: - DeadStoreObs(ASTContext &ctx, BugReporter& br, ParentMap& parents, + DeadStoreObs(const CFG &cfg, ASTContext &ctx, + BugReporter& br, ParentMap& parents, llvm::SmallPtrSet<VarDecl*, 20> &escaped) - : Ctx(ctx), BR(br), Parents(parents), Escaped(escaped) {} + : cfg(cfg), Ctx(ctx), BR(br), Parents(parents), + Escaped(escaped), currentBlock(0) {} virtual ~DeadStoreObs() {} void Report(VarDecl* V, DeadStoreKind dsk, SourceLocation L, SourceRange R) { if (Escaped.count(V)) return; + + // Compute reachable blocks within the CFG for trivial cases + // where a bogus dead store can be reported because itself is unreachable. + if (!reachableCode.get()) { + reachableCode.reset(new ReachableCode(cfg)); + reachableCode->computeReachableBlocks(); + } + + if (!reachableCode->isReachable(currentBlock)) + return; - std::string name = V->getNameAsString(); + const std::string &name = V->getNameAsString(); const char* BugType = 0; std::string msg; @@ -127,10 +181,12 @@ public: return false; } - virtual void ObserveStmt(Stmt* S, + virtual void ObserveStmt(Stmt* S, const CFGBlock *block, const LiveVariables::AnalysisDataTy& AD, const LiveVariables::ValTy& Live) { + currentBlock = block; + // Skip statements in macros. if (S->getLocStart().isMacroID()) return; @@ -284,6 +340,6 @@ void ento::CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &pmap, BugReporter& BR) { FindEscaped FS(&cfg); FS.getCFG().VisitBlockStmts(FS); - DeadStoreObs A(BR.getContext(), BR, pmap, FS.Escaped); + DeadStoreObs A(cfg, BR.getContext(), BR, pmap, FS.Escaped); L.runOnAllBlocks(cfg, &A); } |