DeadStoresChecker.cpp revision 7dd445ec20e704846cfbdb132e56539280d71311
1//==- DeadStoresChecker.cpp - Check for stores to dead variables -*- C++ -*-==//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  This file defines a DeadStores, a flow-sensitive checker that looks for
11//  stores to variables that are no longer live.
12//
13//===----------------------------------------------------------------------===//
14
15#include "ClangSACheckers.h"
16#include "clang/StaticAnalyzer/Core/CheckerV2.h"
17#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
18#include "clang/Analysis/Analyses/LiveVariables.h"
19#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
20#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
21#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
22#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
23#include "clang/Basic/Diagnostic.h"
24#include "clang/AST/ASTContext.h"
25#include "clang/AST/ParentMap.h"
26#include "llvm/ADT/SmallPtrSet.h"
27
28using namespace clang;
29using namespace ento;
30
31namespace {
32
33// FIXME: Eventually migrate into its own file, and have it managed by
34// AnalysisManager.
35class ReachableCode {
36  const CFG &cfg;
37  llvm::BitVector reachable;
38public:
39  ReachableCode(const CFG &cfg)
40    : cfg(cfg), reachable(cfg.getNumBlockIDs(), false) {}
41
42  void computeReachableBlocks();
43
44  bool isReachable(const CFGBlock *block) const {
45    return reachable[block->getBlockID()];
46  }
47};
48}
49
50void ReachableCode::computeReachableBlocks() {
51  if (!cfg.getNumBlockIDs())
52    return;
53
54  llvm::SmallVector<const CFGBlock*, 10> worklist;
55  worklist.push_back(&cfg.getEntry());
56
57  while (!worklist.empty()) {
58    const CFGBlock *block = worklist.back();
59    worklist.pop_back();
60    llvm::BitVector::reference isReachable = reachable[block->getBlockID()];
61    if (isReachable)
62      continue;
63    isReachable = true;
64    for (CFGBlock::const_succ_iterator i = block->succ_begin(),
65                                       e = block->succ_end(); i != e; ++i)
66      if (const CFGBlock *succ = *i)
67        worklist.push_back(succ);
68  }
69}
70
71namespace {
72class DeadStoreObs : public LiveVariables::ObserverTy {
73  const CFG &cfg;
74  ASTContext &Ctx;
75  BugReporter& BR;
76  ParentMap& Parents;
77  llvm::SmallPtrSet<VarDecl*, 20> Escaped;
78  llvm::OwningPtr<ReachableCode> reachableCode;
79  const CFGBlock *currentBlock;
80
81  enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
82
83public:
84  DeadStoreObs(const CFG &cfg, ASTContext &ctx,
85               BugReporter& br, ParentMap& parents,
86               llvm::SmallPtrSet<VarDecl*, 20> &escaped)
87    : cfg(cfg), Ctx(ctx), BR(br), Parents(parents),
88      Escaped(escaped), currentBlock(0) {}
89
90  virtual ~DeadStoreObs() {}
91
92  void Report(VarDecl* V, DeadStoreKind dsk, SourceLocation L, SourceRange R) {
93    if (Escaped.count(V))
94      return;
95
96    // Compute reachable blocks within the CFG for trivial cases
97    // where a bogus dead store can be reported because itself is unreachable.
98    if (!reachableCode.get()) {
99      reachableCode.reset(new ReachableCode(cfg));
100      reachableCode->computeReachableBlocks();
101    }
102
103    if (!reachableCode->isReachable(currentBlock))
104      return;
105
106    const std::string &name = V->getNameAsString();
107
108    const char* BugType = 0;
109    std::string msg;
110
111    switch (dsk) {
112      default:
113        assert(false && "Impossible dead store type.");
114
115      case DeadInit:
116        BugType = "Dead initialization";
117        msg = "Value stored to '" + name +
118          "' during its initialization is never read";
119        break;
120
121      case DeadIncrement:
122        BugType = "Dead increment";
123      case Standard:
124        if (!BugType) BugType = "Dead assignment";
125        msg = "Value stored to '" + name + "' is never read";
126        break;
127
128      case Enclosing:
129        // Don't report issues in this case, e.g.: "if (x = foo())",
130        // where 'x' is unused later.  We have yet to see a case where
131        // this is a real bug.
132        return;
133    }
134
135    BR.EmitBasicReport(BugType, "Dead store", msg, L, R);
136  }
137
138  void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val,
139                    DeadStoreKind dsk,
140                    const LiveVariables::AnalysisDataTy& AD,
141                    const LiveVariables::ValTy& Live) {
142
143    if (!VD->hasLocalStorage())
144      return;
145    // Reference types confuse the dead stores checker.  Skip them
146    // for now.
147    if (VD->getType()->getAs<ReferenceType>())
148      return;
149
150    if (!Live(VD, AD) &&
151        !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>()))
152      Report(VD, dsk, Ex->getSourceRange().getBegin(),
153             Val->getSourceRange());
154  }
155
156  void CheckDeclRef(DeclRefExpr* DR, Expr* Val, DeadStoreKind dsk,
157                    const LiveVariables::AnalysisDataTy& AD,
158                    const LiveVariables::ValTy& Live) {
159    if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
160      CheckVarDecl(VD, DR, Val, dsk, AD, Live);
161  }
162
163  bool isIncrement(VarDecl* VD, BinaryOperator* B) {
164    if (B->isCompoundAssignmentOp())
165      return true;
166
167    Expr* RHS = B->getRHS()->IgnoreParenCasts();
168    BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS);
169
170    if (!BRHS)
171      return false;
172
173    DeclRefExpr *DR;
174
175    if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts())))
176      if (DR->getDecl() == VD)
177        return true;
178
179    if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts())))
180      if (DR->getDecl() == VD)
181        return true;
182
183    return false;
184  }
185
186  virtual void ObserveStmt(Stmt* S, const CFGBlock *block,
187                           const LiveVariables::AnalysisDataTy& AD,
188                           const LiveVariables::ValTy& Live) {
189
190    currentBlock = block;
191
192    // Skip statements in macros.
193    if (S->getLocStart().isMacroID())
194      return;
195
196    // Only cover dead stores from regular assignments.  ++/-- dead stores
197    // have never flagged a real bug.
198    if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
199      if (!B->isAssignmentOp()) return; // Skip non-assignments.
200
201      if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()))
202        if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
203          // Special case: check for assigning null to a pointer.
204          //  This is a common form of defensive programming.
205          QualType T = VD->getType();
206          if (T->isPointerType() || T->isObjCObjectPointerType()) {
207            if (B->getRHS()->isNullPointerConstant(Ctx,
208                                              Expr::NPC_ValueDependentIsNull))
209              return;
210          }
211
212          Expr* RHS = B->getRHS()->IgnoreParenCasts();
213          // Special case: self-assignments.  These are often used to shut up
214          //  "unused variable" compiler warnings.
215          if (DeclRefExpr* RhsDR = dyn_cast<DeclRefExpr>(RHS))
216            if (VD == dyn_cast<VarDecl>(RhsDR->getDecl()))
217              return;
218
219          // Otherwise, issue a warning.
220          DeadStoreKind dsk = Parents.isConsumedExpr(B)
221                              ? Enclosing
222                              : (isIncrement(VD,B) ? DeadIncrement : Standard);
223
224          CheckVarDecl(VD, DR, B->getRHS(), dsk, AD, Live);
225        }
226    }
227    else if (UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
228      if (!U->isIncrementOp() || U->isPrefix())
229        return;
230
231      Stmt *parent = Parents.getParentIgnoreParenCasts(U);
232      if (!parent || !isa<ReturnStmt>(parent))
233        return;
234
235      Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
236
237      if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(Ex))
238        CheckDeclRef(DR, U, DeadIncrement, AD, Live);
239    }
240    else if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
241      // Iterate through the decls.  Warn if any initializers are complex
242      // expressions that are not live (never used).
243      for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end();
244           DI != DE; ++DI) {
245
246        VarDecl* V = dyn_cast<VarDecl>(*DI);
247
248        if (!V)
249          continue;
250
251        if (V->hasLocalStorage()) {
252          // Reference types confuse the dead stores checker.  Skip them
253          // for now.
254          if (V->getType()->getAs<ReferenceType>())
255            return;
256
257          if (Expr* E = V->getInit()) {
258            // Don't warn on C++ objects (yet) until we can show that their
259            // constructors/destructors don't have side effects.
260            if (isa<CXXConstructExpr>(E))
261              return;
262
263            if (isa<ExprWithCleanups>(E))
264              return;
265
266            // A dead initialization is a variable that is dead after it
267            // is initialized.  We don't flag warnings for those variables
268            // marked 'unused'.
269            if (!Live(V, AD) && V->getAttr<UnusedAttr>() == 0) {
270              // Special case: check for initializations with constants.
271              //
272              //  e.g. : int x = 0;
273              //
274              // If x is EVER assigned a new value later, don't issue
275              // a warning.  This is because such initialization can be
276              // due to defensive programming.
277              if (E->isConstantInitializer(Ctx, false))
278                return;
279
280              if (DeclRefExpr *DRE=dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
281                if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
282                  // Special case: check for initialization from constant
283                  //  variables.
284                  //
285                  //  e.g. extern const int MyConstant;
286                  //       int x = MyConstant;
287                  //
288                  if (VD->hasGlobalStorage() &&
289                      VD->getType().isConstQualified())
290                    return;
291                  // Special case: check for initialization from scalar
292                  //  parameters.  This is often a form of defensive
293                  //  programming.  Non-scalars are still an error since
294                  //  because it more likely represents an actual algorithmic
295                  //  bug.
296                  if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType())
297                    return;
298                }
299
300              Report(V, DeadInit, V->getLocation(), E->getSourceRange());
301            }
302          }
303        }
304      }
305  }
306};
307
308} // end anonymous namespace
309
310//===----------------------------------------------------------------------===//
311// Driver function to invoke the Dead-Stores checker on a CFG.
312//===----------------------------------------------------------------------===//
313
314namespace {
315class FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{
316  CFG *cfg;
317public:
318  FindEscaped(CFG *c) : cfg(c) {}
319
320  CFG& getCFG() { return *cfg; }
321
322  llvm::SmallPtrSet<VarDecl*, 20> Escaped;
323
324  void VisitUnaryOperator(UnaryOperator* U) {
325    // Check for '&'.  Any VarDecl whose value has its address-taken we
326    // treat as escaped.
327    Expr* E = U->getSubExpr()->IgnoreParenCasts();
328    if (U->getOpcode() == UO_AddrOf)
329      if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E))
330        if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
331          Escaped.insert(VD);
332          return;
333        }
334    Visit(E);
335  }
336};
337} // end anonymous namespace
338
339
340//===----------------------------------------------------------------------===//
341// DeadStoresChecker
342//===----------------------------------------------------------------------===//
343
344namespace {
345class DeadStoresChecker : public CheckerV2<check::ASTCodeBody> {
346public:
347  void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
348                        BugReporter &BR) const {
349    if (LiveVariables *L = mgr.getLiveVariables(D)) {
350      CFG &cfg = *mgr.getCFG(D);
351      ParentMap &pmap = mgr.getParentMap(D);
352      FindEscaped FS(&cfg);
353      FS.getCFG().VisitBlockStmts(FS);
354      DeadStoreObs A(cfg, BR.getContext(), BR, pmap, FS.Escaped);
355      L->runOnAllBlocks(cfg, &A);
356    }
357  }
358};
359}
360
361void ento::registerDeadStoresChecker(CheckerManager &mgr) {
362  mgr.registerChecker<DeadStoresChecker>();
363}
364