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