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