DeadStoresChecker.cpp revision ebd42f40803396d63bc59b77285d088cca61f53f
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 1597053091c0e4df12ffb662b284b6ab329ca1c40fTed Kremenek#include "clang/Checker/Checkers/LocalCheckers.h" 16cf6e41baf2b23b6b56f0f79fff5554b7745737acTed Kremenek#include "clang/Analysis/Analyses/LiveVariables.h" 17fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h" 186b67630d5df195f4fe0e4273061c016901d69681Ted Kremenek#include "clang/Checker/BugReporter/BugReporter.h" 191309f9a3b225ea846e5822691c39a77423125505Ted Kremenek#include "clang/Checker/PathSensitive/GRExprEngine.h" 20f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" 211ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek#include "clang/Basic/Diagnostic.h" 22ce1cab9fc0b4aec9cdef1b30a14e4ccdca3ac5f1Ted Kremenek#include "clang/AST/ASTContext.h" 231a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek#include "clang/AST/ParentMap.h" 24f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek#include "llvm/ADT/SmallPtrSet.h" 251ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek 261ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenekusing namespace clang; 271ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek 281ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremeneknamespace { 291a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek 30ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass DeadStoreObs : public LiveVariables::ObserverTy { 31c0508f9fe37a3afb1ccad39879348272545e55dbChris Lattner ASTContext &Ctx; 328f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek BugReporter& BR; 331a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek ParentMap& Parents; 34f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek llvm::SmallPtrSet<VarDecl*, 20> Escaped; 351eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 362cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit }; 371eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 381ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenekpublic: 39f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek DeadStoreObs(ASTContext &ctx, BugReporter& br, ParentMap& parents, 40f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek llvm::SmallPtrSet<VarDecl*, 20> &escaped) 41f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek : Ctx(ctx), BR(br), Parents(parents), Escaped(escaped) {} 421eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 43fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek virtual ~DeadStoreObs() {} 44b930d7adb7cb7642c9c49b39df04ebd5cbfa713aTed Kremenek 452cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek void Report(VarDecl* V, DeadStoreKind dsk, SourceLocation L, SourceRange R) { 46f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek if (Escaped.count(V)) 47f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek return; 488f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek 49d9d22dd9c94618490dbffb0e2caf222530ca39d3Chris Lattner std::string name = V->getNameAsString(); 501eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 512cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek const char* BugType = 0; 522cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek std::string msg; 531eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 542cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek switch (dsk) { 552cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek default: 562cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek assert(false && "Impossible dead store type."); 571eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 582cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek case DeadInit: 59efc620c4eb14d2ff59e3ec0714602997ffeddfd7Ted Kremenek BugType = "Dead initialization"; 602cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek msg = "Value stored to '" + name + 612cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek "' during its initialization is never read"; 622cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek break; 631eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 642cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek case DeadIncrement: 65efc620c4eb14d2ff59e3ec0714602997ffeddfd7Ted Kremenek BugType = "Dead increment"; 662cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek case Standard: 67efc620c4eb14d2ff59e3ec0714602997ffeddfd7Ted Kremenek if (!BugType) BugType = "Dead assignment"; 682cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek msg = "Value stored to '" + name + "' is never read"; 692cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek break; 701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 712cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek case Enclosing: 72efc620c4eb14d2ff59e3ec0714602997ffeddfd7Ted Kremenek BugType = "Dead nested assignment"; 732cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek msg = "Although the value stored to '" + name + 742cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek "' is used in the enclosing expression, the value is never actually" 752cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek " read from '" + name + "'"; 762cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek break; 77f9c2a5d1b49b60962b613a1dfffa23831ca298a2Ted Kremenek } 781eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 79f0171732efb4647772ad2a45c0f31978b0e34f71Benjamin Kramer BR.EmitBasicReport(BugType, "Dead store", msg, L, R); 801a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek } 811eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 821a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val, 832cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek DeadStoreKind dsk, 841a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek const LiveVariables::AnalysisDataTy& AD, 851a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek const LiveVariables::ValTy& Live) { 861a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek 87852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek if (!VD->hasLocalStorage()) 88852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek return; 89852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek // Reference types confuse the dead stores checker. Skip them 90852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek // for now. 91852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek if (VD->getType()->getAs<ReferenceType>()) 92852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek return; 93852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek 94852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek if (!Live(VD, AD) && 9574635d8cd3c367890735dc4af2c2825a7e4b434cTed Kremenek !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) 962cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek Report(VD, dsk, Ex->getSourceRange().getBegin(), 971eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump Val->getSourceRange()); 983eb817e5095d25e7bf4a8df9ed3f9b13bed6f298Ted Kremenek } 991eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1002cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek void CheckDeclRef(DeclRefExpr* DR, Expr* Val, DeadStoreKind dsk, 101a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek const LiveVariables::AnalysisDataTy& AD, 102a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek const LiveVariables::ValTy& Live) { 103a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) 1042cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek CheckVarDecl(VD, DR, Val, dsk, AD, Live); 1052cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek } 1061eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1072cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek bool isIncrement(VarDecl* VD, BinaryOperator* B) { 1082cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek if (B->isCompoundAssignmentOp()) 1092cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek return true; 1101eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1112cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek Expr* RHS = B->getRHS()->IgnoreParenCasts(); 1122cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS); 1131eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1142cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek if (!BRHS) 1152cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek return false; 1161eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1172cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek DeclRefExpr *DR; 1181eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1192cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts()))) 1202cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek if (DR->getDecl() == VD) 1212cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek return true; 1221eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1232cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts()))) 1242cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek if (DR->getDecl() == VD) 1252cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek return true; 1261eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1272cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek return false; 128a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek } 1291eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 130fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek virtual void ObserveStmt(Stmt* S, 131fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek const LiveVariables::AnalysisDataTy& AD, 132fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek const LiveVariables::ValTy& Live) { 1331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1341c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek // Skip statements in macros. 1351c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek if (S->getLocStart().isMacroID()) 1361c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek return; 1371eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1381eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) { 139fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek if (!B->isAssignmentOp()) return; // Skip non-assignments. 1401eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 141c0576ca6c6ba136e583985041bd324b0acc38f40Ted Kremenek if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS())) 1421a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 143e12691c2a2109016df12b2cbf54d51a921e6b618Ted Kremenek // Special case: check for assigning null to a pointer. 1441eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump // This is a common form of defensive programming. 145891322002b5f5886d812f6e8df12174fb2d8e73bTed Kremenek QualType T = VD->getType(); 146891322002b5f5886d812f6e8df12174fb2d8e73bTed Kremenek if (T->isPointerType() || T->isObjCObjectPointerType()) { 14793fab7c94008d9e2b1e4ce15784544c6710945feTed Kremenek if (B->getRHS()->isNullPointerConstant(Ctx, 14893fab7c94008d9e2b1e4ce15784544c6710945feTed Kremenek Expr::NPC_ValueDependentIsNull)) 14993fab7c94008d9e2b1e4ce15784544c6710945feTed Kremenek return; 150e12691c2a2109016df12b2cbf54d51a921e6b618Ted Kremenek } 15193fab7c94008d9e2b1e4ce15784544c6710945feTed Kremenek 15293fab7c94008d9e2b1e4ce15784544c6710945feTed Kremenek Expr* RHS = B->getRHS()->IgnoreParenCasts(); 1533b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek // Special case: self-assignments. These are often used to shut up 1543b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek // "unused variable" compiler warnings. 1553b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek if (DeclRefExpr* RhsDR = dyn_cast<DeclRefExpr>(RHS)) 1563b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek if (VD == dyn_cast<VarDecl>(RhsDR->getDecl())) 1573b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek return; 1581eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1593b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek // Otherwise, issue a warning. 160b930d7adb7cb7642c9c49b39df04ebd5cbfa713aTed Kremenek DeadStoreKind dsk = Parents.isConsumedExpr(B) 1611eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump ? Enclosing 1627f5fce7200fdbf03f7d70134a57271e584fcb766Ted Kremenek : (isIncrement(VD,B) ? DeadIncrement : Standard); 1631eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 164e12691c2a2109016df12b2cbf54d51a921e6b618Ted Kremenek CheckVarDecl(VD, DR, B->getRHS(), dsk, AD, Live); 1651eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump } 1661ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek } 167a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek else if (UnaryOperator* U = dyn_cast<UnaryOperator>(S)) { 168a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek if (!U->isIncrementOp()) 169a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek return; 1701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 171380277e46ec1d2d9abedcddf357ceea935cbe576Ted Kremenek // Handle: ++x within a subexpression. The solution is not warn 172380277e46ec1d2d9abedcddf357ceea935cbe576Ted Kremenek // about preincrements to dead variables when the preincrement occurs 173380277e46ec1d2d9abedcddf357ceea935cbe576Ted Kremenek // as a subexpression. This can lead to false negatives, e.g. "(++x);" 174380277e46ec1d2d9abedcddf357ceea935cbe576Ted Kremenek // A generalized dead code checker should find such issues. 175b930d7adb7cb7642c9c49b39df04ebd5cbfa713aTed Kremenek if (U->isPrefix() && Parents.isConsumedExpr(U)) 176380277e46ec1d2d9abedcddf357ceea935cbe576Ted Kremenek return; 177b0f36323d9d8392075274b95816e2241f99ddb0dTed Kremenek 178a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek Expr *Ex = U->getSubExpr()->IgnoreParenCasts(); 1791eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 180a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(Ex)) 1812cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek CheckDeclRef(DR, U, DeadIncrement, AD, Live); 1821eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump } 183a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek else if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) 184fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek // Iterate through the decls. Warn if any initializers are complex 185fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek // expressions that are not live (never used). 18614f8b4ff660bcaa763974b8d0fae81857c594495Ted Kremenek for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end(); 18714f8b4ff660bcaa763974b8d0fae81857c594495Ted Kremenek DI != DE; ++DI) { 1881eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 18914f8b4ff660bcaa763974b8d0fae81857c594495Ted Kremenek VarDecl* V = dyn_cast<VarDecl>(*DI); 190fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek 191fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek if (!V) 192fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek continue; 193852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek 194852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek if (V->hasLocalStorage()) { 195852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek // Reference types confuse the dead stores checker. Skip them 196852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek // for now. 197852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek if (V->getType()->getAs<ReferenceType>()) 198852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek return; 199852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek 200fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek if (Expr* E = V->getInit()) { 20143f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek // Don't warn on C++ objects (yet) until we can show that their 20243f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek // constructors/destructors don't have side effects. 20343f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek if (isa<CXXConstructExpr>(E)) 20443f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek return; 205604d939ac15d1398761df313679673d30bb10f27Ted Kremenek 206604d939ac15d1398761df313679673d30bb10f27Ted Kremenek if (isa<CXXExprWithTemporaries>(E)) 207604d939ac15d1398761df313679673d30bb10f27Ted Kremenek return; 208604d939ac15d1398761df313679673d30bb10f27Ted Kremenek 209fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek // A dead initialization is a variable that is dead after it 210fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek // is initialized. We don't flag warnings for those variables 211fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek // marked 'unused'. 21240b598eea1310ec9ed554d56ce3e25b34c585458Argyrios Kyrtzidis if (!Live(V, AD) && V->getAttr<UnusedAttr>() == 0) { 213c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek // Special case: check for initializations with constants. 214c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek // 215c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek // e.g. : int x = 0; 216c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek // 217c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek // If x is EVER assigned a new value later, don't issue 218c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek // a warning. This is because such initialization can be 219c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek // due to defensive programming. 220d3098ee64c069a3eff4d2d0a5d655d968c7b5dd2Ted Kremenek if (E->isConstantInitializer(Ctx)) 221d3098ee64c069a3eff4d2d0a5d655d968c7b5dd2Ted Kremenek return; 2221eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 223d3098ee64c069a3eff4d2d0a5d655d968c7b5dd2Ted Kremenek if (DeclRefExpr *DRE=dyn_cast<DeclRefExpr>(E->IgnoreParenCasts())) 224ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { 225ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // Special case: check for initialization from constant 226ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // variables. 227ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // 228ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // e.g. extern const int MyConstant; 229ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // int x = MyConstant; 230ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // 231d3098ee64c069a3eff4d2d0a5d655d968c7b5dd2Ted Kremenek if (VD->hasGlobalStorage() && 232ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek VD->getType().isConstQualified()) 233ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek return; 234ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // Special case: check for initialization from scalar 235ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // parameters. This is often a form of defensive 236ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // programming. Non-scalars are still an error since 237ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // because it more likely represents an actual algorithmic 238ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek // bug. 239ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType()) 240ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek return; 241ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek } 2421eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 243d3098ee64c069a3eff4d2d0a5d655d968c7b5dd2Ted Kremenek Report(V, DeadInit, V->getLocation(), E->getSourceRange()); 244ce1cab9fc0b4aec9cdef1b30a14e4ccdca3ac5f1Ted Kremenek } 245fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek } 246852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek } 247fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek } 2481ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek } 2491ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek}; 2501eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2511ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek} // end anonymous namespace 2521ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek 253d2f642b56e87493edfc3b0dab359b5e32d5f8a5eTed Kremenek//===----------------------------------------------------------------------===// 254e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenek// Driver function to invoke the Dead-Stores checker on a CFG. 255e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenek//===----------------------------------------------------------------------===// 256e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenek 257f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremeneknamespace { 258ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{ 259f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek CFG *cfg; 260f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenekpublic: 261f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek FindEscaped(CFG *c) : cfg(c) {} 2621eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 263f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek CFG& getCFG() { return *cfg; } 2641eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 265f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek llvm::SmallPtrSet<VarDecl*, 20> Escaped; 266f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek 267f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek void VisitUnaryOperator(UnaryOperator* U) { 268f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek // Check for '&'. Any VarDecl whose value has its address-taken we 269f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek // treat as escaped. 270f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek Expr* E = U->getSubExpr()->IgnoreParenCasts(); 271f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek if (U->getOpcode() == UnaryOperator::AddrOf) 272f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E)) 273f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) { 274f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek Escaped.insert(VD); 275f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek return; 276f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek } 277f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek Visit(E); 278f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek } 279f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek}; 280f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek} // end anonymous namespace 2811eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 282f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek 283b317f8f5ca8737a5bbad97a3f7566a2dbd2ed61bZhongxing Xuvoid clang::CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &pmap, 284b317f8f5ca8737a5bbad97a3f7566a2dbd2ed61bZhongxing Xu BugReporter& BR) { 285b317f8f5ca8737a5bbad97a3f7566a2dbd2ed61bZhongxing Xu FindEscaped FS(&cfg); 2861eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump FS.getCFG().VisitBlockStmts(FS); 287b317f8f5ca8737a5bbad97a3f7566a2dbd2ed61bZhongxing Xu DeadStoreObs A(BR.getContext(), BR, pmap, FS.Escaped); 288b317f8f5ca8737a5bbad97a3f7566a2dbd2ed61bZhongxing Xu L.runOnAllBlocks(cfg, &A); 289d2f642b56e87493edfc3b0dab359b5e32d5f8a5eTed Kremenek} 290