DeadStoresChecker.cpp revision 9c378f705405d37f49795d5e915989de774fe11f
156b1f71156db11b9c8234ca621c29213a73218e0Ted Kremenek//==- DeadStoresChecker.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 157dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis#include "ClangSACheckers.h" 16ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h" 17cf6e41baf2b23b6b56f0f79fff5554b7745737acTed Kremenek#include "clang/Analysis/Analyses/LiveVariables.h" 18fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h" 199b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 209b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 21f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" 221ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek#include "clang/Basic/Diagnostic.h" 23ce1cab9fc0b4aec9cdef1b30a14e4ccdca3ac5f1Ted Kremenek#include "clang/AST/ASTContext.h" 241a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek#include "clang/AST/ParentMap.h" 25f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek#include "llvm/ADT/SmallPtrSet.h" 261ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek 271ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenekusing namespace clang; 289ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento; 291ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek 301ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremeneknamespace { 311a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek 32848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek// FIXME: Eventually migrate into its own file, and have it managed by 33848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek// AnalysisManager. 34848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenekclass ReachableCode { 35848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek const CFG &cfg; 36848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek llvm::BitVector reachable; 37848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenekpublic: 38848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek ReachableCode(const CFG &cfg) 39848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek : cfg(cfg), reachable(cfg.getNumBlockIDs(), false) {} 40848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek 41848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek void computeReachableBlocks(); 42848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek 43848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek bool isReachable(const CFGBlock *block) const { 44848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek return reachable[block->getBlockID()]; 45848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek } 46848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek}; 47848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek} 48848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek 49848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenekvoid ReachableCode::computeReachableBlocks() { 50848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek if (!cfg.getNumBlockIDs()) 51848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek return; 52848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek 535f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner SmallVector<const CFGBlock*, 10> worklist; 54848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek worklist.push_back(&cfg.getEntry()); 55848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek 56848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek while (!worklist.empty()) { 57848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek const CFGBlock *block = worklist.back(); 58848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek worklist.pop_back(); 59848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek llvm::BitVector::reference isReachable = reachable[block->getBlockID()]; 60848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek if (isReachable) 61848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek continue; 62848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek isReachable = true; 63848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek for (CFGBlock::const_succ_iterator i = block->succ_begin(), 64848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek e = block->succ_end(); i != e; ++i) 65848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek if (const CFGBlock *succ = *i) 66848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek worklist.push_back(succ); 67848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek } 68848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek} 69848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek 70848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremeneknamespace { 71882998923889a2fcce9b49696506c499e22cf38fTed Kremenekclass DeadStoreObs : public LiveVariables::Observer { 72848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek const CFG &cfg; 73c0508f9fe37a3afb1ccad39879348272545e55dbChris Lattner ASTContext &Ctx; 748f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek BugReporter& BR; 751a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek ParentMap& Parents; 76882998923889a2fcce9b49696506c499e22cf38fTed Kremenek llvm::SmallPtrSet<const VarDecl*, 20> Escaped; 77848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek llvm::OwningPtr<ReachableCode> reachableCode; 78848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek const CFGBlock *currentBlock; 791eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 802cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit }; 811eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 821ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenekpublic: 83848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek DeadStoreObs(const CFG &cfg, ASTContext &ctx, 84848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek BugReporter& br, ParentMap& parents, 85882998923889a2fcce9b49696506c499e22cf38fTed Kremenek llvm::SmallPtrSet<const VarDecl*, 20> &escaped) 86848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek : cfg(cfg), Ctx(ctx), BR(br), Parents(parents), 87848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek Escaped(escaped), currentBlock(0) {} 881eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 89fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek virtual ~DeadStoreObs() {} 90b930d7adb7cb7642c9c49b39df04ebd5cbfa713aTed Kremenek 919c378f705405d37f49795d5e915989de774fe11fTed Kremenek void Report(const VarDecl *V, DeadStoreKind dsk, 92882998923889a2fcce9b49696506c499e22cf38fTed Kremenek SourceLocation L, SourceRange R) { 93f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek if (Escaped.count(V)) 94f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek return; 95848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek 96848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek // Compute reachable blocks within the CFG for trivial cases 97848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek // where a bogus dead store can be reported because itself is unreachable. 98848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek if (!reachableCode.get()) { 99848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek reachableCode.reset(new ReachableCode(cfg)); 100848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek reachableCode->computeReachableBlocks(); 101848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek } 102848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek 103848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek if (!reachableCode->isReachable(currentBlock)) 104848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek return; 1058f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek 106848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek const std::string &name = V->getNameAsString(); 1071eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1082cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek const char* BugType = 0; 1092cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek std::string msg; 1101eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1112cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek switch (dsk) { 1122cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek default: 1132cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek assert(false && "Impossible dead store type."); 1141eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1152cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek case DeadInit: 116efc620c4eb14d2ff59e3ec0714602997ffeddfd7Ted Kremenek BugType = "Dead initialization"; 1172cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek msg = "Value stored to '" + name + 1182cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek "' during its initialization is never read"; 1192cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek break; 1201eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1212cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek case DeadIncrement: 122efc620c4eb14d2ff59e3ec0714602997ffeddfd7Ted Kremenek BugType = "Dead increment"; 1232cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek case Standard: 124efc620c4eb14d2ff59e3ec0714602997ffeddfd7Ted Kremenek if (!BugType) BugType = "Dead assignment"; 1252cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek msg = "Value stored to '" + name + "' is never read"; 1262cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek break; 1271eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1282cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek case Enclosing: 12956b1f71156db11b9c8234ca621c29213a73218e0Ted Kremenek // Don't report issues in this case, e.g.: "if (x = foo())", 13056b1f71156db11b9c8234ca621c29213a73218e0Ted Kremenek // where 'x' is unused later. We have yet to see a case where 13156b1f71156db11b9c8234ca621c29213a73218e0Ted Kremenek // this is a real bug. 13256b1f71156db11b9c8234ca621c29213a73218e0Ted Kremenek return; 133f9c2a5d1b49b60962b613a1dfffa23831ca298a2Ted Kremenek } 1341eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 135f0171732efb4647772ad2a45c0f31978b0e34f71Benjamin Kramer BR.EmitBasicReport(BugType, "Dead store", msg, L, R); 1361a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek } 1371eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1389c378f705405d37f49795d5e915989de774fe11fTed Kremenek void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val, 1392cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek DeadStoreKind dsk, 140882998923889a2fcce9b49696506c499e22cf38fTed Kremenek const LiveVariables::LivenessValues &Live) { 1411a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek 142852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek if (!VD->hasLocalStorage()) 143852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek return; 144852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek // Reference types confuse the dead stores checker. Skip them 145852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek // for now. 146852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek if (VD->getType()->getAs<ReferenceType>()) 147852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek return; 148852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek 149882998923889a2fcce9b49696506c499e22cf38fTed Kremenek if (!Live.isLive(VD) && 15074635d8cd3c367890735dc4af2c2825a7e4b434cTed Kremenek !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) 1512cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek Report(VD, dsk, Ex->getSourceRange().getBegin(), 1521eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump Val->getSourceRange()); 1533eb817e5095d25e7bf4a8df9ed3f9b13bed6f298Ted Kremenek } 1541eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1559c378f705405d37f49795d5e915989de774fe11fTed Kremenek void CheckDeclRef(const DeclRefExpr *DR, const Expr *Val, DeadStoreKind dsk, 156882998923889a2fcce9b49696506c499e22cf38fTed Kremenek const LiveVariables::LivenessValues& Live) { 1579c378f705405d37f49795d5e915989de774fe11fTed Kremenek if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) 158882998923889a2fcce9b49696506c499e22cf38fTed Kremenek CheckVarDecl(VD, DR, Val, dsk, Live); 1592cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek } 1601eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1619c378f705405d37f49795d5e915989de774fe11fTed Kremenek bool isIncrement(VarDecl *VD, const BinaryOperator* B) { 1622cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek if (B->isCompoundAssignmentOp()) 1632cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek return true; 1641eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1659c378f705405d37f49795d5e915989de774fe11fTed Kremenek const Expr *RHS = B->getRHS()->IgnoreParenCasts(); 166882998923889a2fcce9b49696506c499e22cf38fTed Kremenek const BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS); 1671eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1682cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek if (!BRHS) 1692cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek return false; 1701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 171882998923889a2fcce9b49696506c499e22cf38fTed Kremenek const DeclRefExpr *DR; 1721eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1732cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts()))) 1742cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek if (DR->getDecl() == VD) 1752cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek return true; 1761eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1772cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts()))) 1782cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek if (DR->getDecl() == VD) 1792cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek return true; 1801eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1812cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek return false; 182a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek } 1831eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1849c378f705405d37f49795d5e915989de774fe11fTed Kremenek virtual void observeStmt(const Stmt *S, const CFGBlock *block, 185882998923889a2fcce9b49696506c499e22cf38fTed Kremenek const LiveVariables::LivenessValues &Live) { 1861eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 187848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek currentBlock = block; 188848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek 1891c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek // Skip statements in macros. 1901c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek if (S->getLocStart().isMacroID()) 1911c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek return; 1921eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 193f4e532b5a1683a9f6c842f361c7415bf3474315fTed Kremenek // Only cover dead stores from regular assignments. ++/-- dead stores 194f4e532b5a1683a9f6c842f361c7415bf3474315fTed Kremenek // have never flagged a real bug. 195882998923889a2fcce9b49696506c499e22cf38fTed Kremenek if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) { 196fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek if (!B->isAssignmentOp()) return; // Skip non-assignments. 1971eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1989c378f705405d37f49795d5e915989de774fe11fTed Kremenek if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS())) 1991a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 200e12691c2a2109016df12b2cbf54d51a921e6b618Ted Kremenek // Special case: check for assigning null to a pointer. 2011eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump // This is a common form of defensive programming. 202891322002b5f5886d812f6e8df12174fb2d8e73bTed Kremenek QualType T = VD->getType(); 203891322002b5f5886d812f6e8df12174fb2d8e73bTed Kremenek if (T->isPointerType() || T->isObjCObjectPointerType()) { 20493fab7c94008d9e2b1e4ce15784544c6710945feTed Kremenek if (B->getRHS()->isNullPointerConstant(Ctx, 20593fab7c94008d9e2b1e4ce15784544c6710945feTed Kremenek Expr::NPC_ValueDependentIsNull)) 20693fab7c94008d9e2b1e4ce15784544c6710945feTed Kremenek return; 207e12691c2a2109016df12b2cbf54d51a921e6b618Ted Kremenek } 20893fab7c94008d9e2b1e4ce15784544c6710945feTed Kremenek 2099c378f705405d37f49795d5e915989de774fe11fTed Kremenek Expr *RHS = B->getRHS()->IgnoreParenCasts(); 2103b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek // Special case: self-assignments. These are often used to shut up 2113b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek // "unused variable" compiler warnings. 2129c378f705405d37f49795d5e915989de774fe11fTed Kremenek if (DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS)) 2133b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek if (VD == dyn_cast<VarDecl>(RhsDR->getDecl())) 2143b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek return; 2151eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2163b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek // Otherwise, issue a warning. 217b930d7adb7cb7642c9c49b39df04ebd5cbfa713aTed Kremenek DeadStoreKind dsk = Parents.isConsumedExpr(B) 2181eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump ? Enclosing 2197f5fce7200fdbf03f7d70134a57271e584fcb766Ted Kremenek : (isIncrement(VD,B) ? DeadIncrement : Standard); 2201eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 221882998923889a2fcce9b49696506c499e22cf38fTed Kremenek CheckVarDecl(VD, DR, B->getRHS(), dsk, Live); 2221eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump } 2231ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek } 224882998923889a2fcce9b49696506c499e22cf38fTed Kremenek else if (const UnaryOperator* U = dyn_cast<UnaryOperator>(S)) { 225f4e532b5a1683a9f6c842f361c7415bf3474315fTed Kremenek if (!U->isIncrementOp() || U->isPrefix()) 226a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek return; 2271eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 228882998923889a2fcce9b49696506c499e22cf38fTed Kremenek const Stmt *parent = Parents.getParentIgnoreParenCasts(U); 229f4e532b5a1683a9f6c842f361c7415bf3474315fTed Kremenek if (!parent || !isa<ReturnStmt>(parent)) 230380277e46ec1d2d9abedcddf357ceea935cbe576Ted Kremenek return; 231b0f36323d9d8392075274b95816e2241f99ddb0dTed Kremenek 232882998923889a2fcce9b49696506c499e22cf38fTed Kremenek const Expr *Ex = U->getSubExpr()->IgnoreParenCasts(); 2331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2349c378f705405d37f49795d5e915989de774fe11fTed Kremenek if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) 235882998923889a2fcce9b49696506c499e22cf38fTed Kremenek CheckDeclRef(DR, U, DeadIncrement, Live); 2361eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump } 2379c378f705405d37f49795d5e915989de774fe11fTed Kremenek else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) 238fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek // Iterate through the decls. Warn if any initializers are complex 239fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek // expressions that are not live (never used). 240882998923889a2fcce9b49696506c499e22cf38fTed Kremenek for (DeclStmt::const_decl_iterator DI=DS->decl_begin(), DE=DS->decl_end(); 24114f8b4ff660bcaa763974b8d0fae81857c594495Ted Kremenek DI != DE; ++DI) { 2421eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2439c378f705405d37f49795d5e915989de774fe11fTed Kremenek VarDecl *V = dyn_cast<VarDecl>(*DI); 244fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek 245fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek if (!V) 246fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek continue; 247852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek 248852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek if (V->hasLocalStorage()) { 249852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek // Reference types confuse the dead stores checker. Skip them 250852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek // for now. 251852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek if (V->getType()->getAs<ReferenceType>()) 252852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek return; 253852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek 2549c378f705405d37f49795d5e915989de774fe11fTed Kremenek if (Expr *E = V->getInit()) { 255f85e193739c953358c865005855253af4f68a497John McCall while (ExprWithCleanups *exprClean = dyn_cast<ExprWithCleanups>(E)) 256f85e193739c953358c865005855253af4f68a497John McCall E = exprClean->getSubExpr(); 257f85e193739c953358c865005855253af4f68a497John McCall 25843f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek // Don't warn on C++ objects (yet) until we can show that their 25943f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek // constructors/destructors don't have side effects. 26043f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek if (isa<CXXConstructExpr>(E)) 26143f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek return; 262604d939ac15d1398761df313679673d30bb10f27Ted Kremenek 263fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek // A dead initialization is a variable that is dead after it 264fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek // is initialized. We don't flag warnings for those variables 265fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek // marked 'unused'. 266882998923889a2fcce9b49696506c499e22cf38fTed Kremenek if (!Live.isLive(V) && V->getAttr<UnusedAttr>() == 0) { 267c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek // Special case: check for initializations with constants. 268c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek // 269c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek // e.g. : int x = 0; 270c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek // 271c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek // If x is EVER assigned a new value later, don't issue 272c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek // a warning. This is because such initialization can be 273c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek // due to defensive programming. 2744204f07fc8bffe6d320b2de95fea274ccf37a17bJohn McCall if (E->isConstantInitializer(Ctx, false)) 275d3098ee64c069a3eff4d2d0a5d655d968c7b5dd2Ted Kremenek return; 2761eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 277d3098ee64c069a3eff4d2d0a5d655d968c7b5dd2Ted Kremenek if (DeclRefExpr *DRE=dyn_cast<DeclRefExpr>(E->IgnoreParenCasts())) 278ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { 279ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // Special case: check for initialization from constant 280ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // variables. 281ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // 282ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // e.g. extern const int MyConstant; 283ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // int x = MyConstant; 284ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // 285d3098ee64c069a3eff4d2d0a5d655d968c7b5dd2Ted Kremenek if (VD->hasGlobalStorage() && 286ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek VD->getType().isConstQualified()) 287ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek return; 288ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // Special case: check for initialization from scalar 289ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // parameters. This is often a form of defensive 290ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // programming. Non-scalars are still an error since 291ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // because it more likely represents an actual algorithmic 292ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // bug. 293ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType()) 294ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek return; 295ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek } 2961eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 297d3098ee64c069a3eff4d2d0a5d655d968c7b5dd2Ted Kremenek Report(V, DeadInit, V->getLocation(), E->getSourceRange()); 298ce1cab9fc0b4aec9cdef1b30a14e4ccdca3ac5f1Ted Kremenek } 299fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek } 300852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek } 301fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek } 3021ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek } 3031ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek}; 3041eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 3051ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek} // end anonymous namespace 3061ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek 307d2f642b56e87493edfc3b0dab359b5e32d5f8a5eTed Kremenek//===----------------------------------------------------------------------===// 308e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenek// Driver function to invoke the Dead-Stores checker on a CFG. 309e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenek//===----------------------------------------------------------------------===// 310e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenek 311f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremeneknamespace { 312ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{ 313f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek CFG *cfg; 314f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenekpublic: 315f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek FindEscaped(CFG *c) : cfg(c) {} 3161eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 317f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek CFG& getCFG() { return *cfg; } 3181eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 319882998923889a2fcce9b49696506c499e22cf38fTed Kremenek llvm::SmallPtrSet<const VarDecl*, 20> Escaped; 320f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek 321f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek void VisitUnaryOperator(UnaryOperator* U) { 322f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek // Check for '&'. Any VarDecl whose value has its address-taken we 323f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek // treat as escaped. 3249c378f705405d37f49795d5e915989de774fe11fTed Kremenek Expr *E = U->getSubExpr()->IgnoreParenCasts(); 3252de56d1d0c3a504ad1529de2677628bdfbb95cd4John McCall if (U->getOpcode() == UO_AddrOf) 3269c378f705405d37f49795d5e915989de774fe11fTed Kremenek if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) 3279c378f705405d37f49795d5e915989de774fe11fTed Kremenek if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 328f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek Escaped.insert(VD); 329f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek return; 330f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek } 331f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek Visit(E); 332f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek } 333f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek}; 334f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek} // end anonymous namespace 3351eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 336f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek 3377dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis//===----------------------------------------------------------------------===// 3387dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis// DeadStoresChecker 3397dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis//===----------------------------------------------------------------------===// 3407dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis 3417dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidisnamespace { 342ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidisclass DeadStoresChecker : public Checker<check::ASTCodeBody> { 3437dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidispublic: 3447dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 3457dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis BugReporter &BR) const { 3467dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis if (LiveVariables *L = mgr.getLiveVariables(D)) { 3477dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis CFG &cfg = *mgr.getCFG(D); 3487dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis ParentMap &pmap = mgr.getParentMap(D); 3497dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis FindEscaped FS(&cfg); 3507dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis FS.getCFG().VisitBlockStmts(FS); 3517dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis DeadStoreObs A(cfg, BR.getContext(), BR, pmap, FS.Escaped); 352882998923889a2fcce9b49696506c499e22cf38fTed Kremenek L->runOnAllBlocks(A); 3537dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis } 3547dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis } 3557dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis}; 3567dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis} 3577dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis 3587dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidisvoid ento::registerDeadStoresChecker(CheckerManager &mgr) { 3597dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis mgr.registerChecker<DeadStoresChecker>(); 360d2f642b56e87493edfc3b0dab359b5e32d5f8a5eTed Kremenek} 361