DeadStoresChecker.cpp revision fc7ff5540412f8003024e1b4940fb8408dff2ca6
11ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//==- DeadStores.cpp - Check for stores to dead variables --------*- C++ -*-==//
21ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//
31ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//                     The LLVM Compiler Infrastructure
41ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//
50bc735ffcfb223c0186419547abaa5c84482663eChris Lattner// This file is distributed under the University of Illinois Open Source
60bc735ffcfb223c0186419547abaa5c84482663eChris Lattner// License. See LICENSE.TXT for details.
71ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//
81ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//===----------------------------------------------------------------------===//
91ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//
10843e934ba8c6ebc00d2f6969a50af7074597e8e3Gabor Greif//  This file defines a DeadStores, a flow-sensitive checker that looks for
111ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//  stores to variables that are no longer live.
121ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//
131ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//===----------------------------------------------------------------------===//
141ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek
151ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek#include "clang/Analysis/LocalCheckers.h"
16cf6e41baf2b23b6b56f0f79fff5554b7745737acTed Kremenek#include "clang/Analysis/Analyses/LiveVariables.h"
17fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
18d2f642b56e87493edfc3b0dab359b5e32d5f8a5eTed Kremenek#include "clang/Analysis/PathSensitive/BugReporter.h"
19d2f642b56e87493edfc3b0dab359b5e32d5f8a5eTed Kremenek#include "clang/Analysis/PathSensitive/GRExprEngine.h"
201ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek#include "clang/Basic/Diagnostic.h"
21ce1cab9fc0b4aec9cdef1b30a14e4ccdca3ac5f1Ted Kremenek#include "clang/AST/ASTContext.h"
221a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek#include "clang/AST/ParentMap.h"
23c2b51d8cf33bed92b68ee0a8e3c28411e43faffdTed Kremenek#include "llvm/Support/Compiler.h"
241ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek
251ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenekusing namespace clang;
261ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek
271ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremeneknamespace {
281a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek
29c2b51d8cf33bed92b68ee0a8e3c28411e43faffdTed Kremenekclass VISIBILITY_HIDDEN DeadStoreObs : public LiveVariables::ObserverTy {
30c0508f9fe37a3afb1ccad39879348272545e55dbChris Lattner  ASTContext &Ctx;
318f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek  BugReporter& BR;
321a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek  ParentMap& Parents;
332cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek
342cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek  enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
351a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek
361ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenekpublic:
378f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek  DeadStoreObs(ASTContext &ctx, BugReporter& br, ParentMap& parents)
388f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek    : Ctx(ctx), BR(br), Parents(parents) {}
39d2f642b56e87493edfc3b0dab359b5e32d5f8a5eTed Kremenek
40fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek  virtual ~DeadStoreObs() {}
41fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek
422cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek  void Report(VarDecl* V, DeadStoreKind dsk, SourceLocation L, SourceRange R) {
438f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek
44f9c2a5d1b49b60962b613a1dfffa23831ca298a2Ted Kremenek    std::string name(V->getName());
45c07ba352b7604435e80269be23ace72a52bd04f1Ted Kremenek
462cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    const char* BugType = 0;
472cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    std::string msg;
48f9c2a5d1b49b60962b613a1dfffa23831ca298a2Ted Kremenek
492cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    switch (dsk) {
502cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      default:
512cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        assert(false && "Impossible dead store type.");
522cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek
532cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      case DeadInit:
542cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        BugType = "dead initialization";
552cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        msg = "Value stored to '" + name +
562cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek          "' during its initialization is never read";
572cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        break;
582cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek
592cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      case DeadIncrement:
602cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        BugType = "dead store (++/--)";
612cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      case Standard:
622cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        if (!BugType) BugType = "dead store";
632cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        msg = "Value stored to '" + name + "' is never read";
642cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        break;
652cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek
662cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      case Enclosing:
672cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        BugType = "dead store";
682cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        msg = "Although the value stored to '" + name +
692cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek          "' is used in the enclosing expression, the value is never actually"
702cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek          " read from '" + name + "'";
712cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        break;
72f9c2a5d1b49b60962b613a1dfffa23831ca298a2Ted Kremenek    }
732cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek
742cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    BR.EmitBasicReport(BugType, msg.c_str(), L, R);
751a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek  }
761a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek
771a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek  void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val,
782cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek                    DeadStoreKind dsk,
791a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek                    const LiveVariables::AnalysisDataTy& AD,
801a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek                    const LiveVariables::ValTy& Live) {
811a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek
828f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek    if (VD->hasLocalStorage() && !Live(VD, AD))
832cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      Report(VD, dsk, Ex->getSourceRange().getBegin(),
848f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek             Val->getSourceRange());
853eb817e5095d25e7bf4a8df9ed3f9b13bed6f298Ted Kremenek  }
863eb817e5095d25e7bf4a8df9ed3f9b13bed6f298Ted Kremenek
872cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek  void CheckDeclRef(DeclRefExpr* DR, Expr* Val, DeadStoreKind dsk,
88a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek                    const LiveVariables::AnalysisDataTy& AD,
89a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek                    const LiveVariables::ValTy& Live) {
90a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek
91a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek    if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
922cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      CheckVarDecl(VD, DR, Val, dsk, AD, Live);
932cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek  }
942cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek
952cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek  bool isIncrement(VarDecl* VD, BinaryOperator* B) {
962cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    if (B->isCompoundAssignmentOp())
972cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      return true;
982cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek
992cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    Expr* RHS = B->getRHS()->IgnoreParenCasts();
1002cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS);
1012cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek
1022cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    if (!BRHS)
1032cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      return false;
1042cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek
1052cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    DeclRefExpr *DR;
1062cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek
1072cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts())))
1082cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      if (DR->getDecl() == VD)
1092cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        return true;
1102cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek
1112cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts())))
1122cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      if (DR->getDecl() == VD)
1132cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        return true;
1142cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek
1152cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    return false;
116a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek  }
117a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek
118fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek  virtual void ObserveStmt(Stmt* S,
119fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek                           const LiveVariables::AnalysisDataTy& AD,
120fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek                           const LiveVariables::ValTy& Live) {
121ce1cab9fc0b4aec9cdef1b30a14e4ccdca3ac5f1Ted Kremenek
1221c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek    // Skip statements in macros.
1231c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek    if (S->getLocStart().isMacroID())
1241c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek      return;
1251c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek
1261ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek    if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
127fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek      if (!B->isAssignmentOp()) return; // Skip non-assignments.
1281ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek
129c0576ca6c6ba136e583985041bd324b0acc38f40Ted Kremenek      if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()))
1301a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek        if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
1311a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek
1321a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek          // Special case: check for assigning null to a pointer.  This
1331a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek          //  is a common form of defensive programming.
1341a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek          // FIXME: Make this optional?
1351a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek
1361a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek          Expr* Val = B->getRHS();
1371a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek          llvm::APSInt Result(Ctx.getTypeSize(Val->getType()));
1381a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek
1391a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek          if (VD->getType()->isPointerType() &&
1401a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek              Val->IgnoreParenCasts()->isIntegerConstantExpr(Result, Ctx, 0))
1411a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek            if (Result == 0)
1421a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek              return;
1431a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek
1442cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek          DeadStoreKind dsk =
1452cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek            Parents.isSubExpr(B)
1462cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek            ? Enclosing
1472cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek            : (isIncrement(VD,B) ? DeadIncrement : Standard);
1482cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek
1492cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek          CheckVarDecl(VD, DR, Val, dsk, AD, Live);
1501a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek        }
1511ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek    }
152a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek    else if (UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
153a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek      if (!U->isIncrementOp())
154a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek        return;
155b0f36323d9d8392075274b95816e2241f99ddb0dTed Kremenek
156a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek      Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
157a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek
158a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek      if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(Ex))
1592cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        CheckDeclRef(DR, U, DeadIncrement, AD, Live);
160a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek    }
161a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek    else if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
162fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek      // Iterate through the decls.  Warn if any initializers are complex
163fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek      // expressions that are not live (never used).
1641c61b472b24e7a61b91d535c030c92cd1fd8c7eeTed Kremenek      for (ScopedDecl* SD = DS->getDecl(); SD; SD = SD->getNextDeclarator()) {
165c967c9d9011a9907e05a5c908ec0b7d2e7f3a11dTed Kremenek
166c967c9d9011a9907e05a5c908ec0b7d2e7f3a11dTed Kremenek        VarDecl* V = dyn_cast<VarDecl>(SD);
167fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek
168fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek        if (!V)
169fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek          continue;
170c967c9d9011a9907e05a5c908ec0b7d2e7f3a11dTed Kremenek
171c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek        if (V->hasLocalStorage())
172fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek          if (Expr* E = V->getInit()) {
173fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek            // A dead initialization is a variable that is dead after it
174fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek            // is initialized.  We don't flag warnings for those variables
175fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek            // marked 'unused'.
176fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek            if (!Live(V, AD) && V->getAttr<UnusedAttr>() == 0) {
177c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              // Special case: check for initializations with constants.
178c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              //
179c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              //  e.g. : int x = 0;
180c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              //
181c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              // If x is EVER assigned a new value later, don't issue
182c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              // a warning.  This is because such initialization can be
183c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              // due to defensive programming.
1848f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek              if (!E->isConstantExpr(Ctx,NULL))
1852cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek                Report(V, DeadInit, V->getLocation(), E->getSourceRange());
186ce1cab9fc0b4aec9cdef1b30a14e4ccdca3ac5f1Ted Kremenek            }
187fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek          }
188fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek      }
1891ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek  }
1901ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek};
1911ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek
1921ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek} // end anonymous namespace
1931ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek
194d2f642b56e87493edfc3b0dab359b5e32d5f8a5eTed Kremenek//===----------------------------------------------------------------------===//
195e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenek// Driver function to invoke the Dead-Stores checker on a CFG.
196e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenek//===----------------------------------------------------------------------===//
197e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenek
198e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenekvoid clang::CheckDeadStores(LiveVariables& L, BugReporter& BR) {
1998f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek  DeadStoreObs A(BR.getContext(), BR, BR.getParentMap());
2007032f460fc9828f386056e75933da5af61e88638Ted Kremenek  L.runOnAllBlocks(*BR.getCFG(), &A);
201d2f642b56e87493edfc3b0dab359b5e32d5f8a5eTed Kremenek}
202