clang API Documentation
00001 //==- DeadStoresChecker.cpp - Check for stores to dead variables -*- C++ -*-==// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines a DeadStores, a flow-sensitive checker that looks for 00011 // stores to variables that are no longer live. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "ClangSACheckers.h" 00016 #include "clang/AST/ASTContext.h" 00017 #include "clang/AST/Attr.h" 00018 #include "clang/AST/ParentMap.h" 00019 #include "clang/AST/RecursiveASTVisitor.h" 00020 #include "clang/Analysis/Analyses/LiveVariables.h" 00021 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 00022 #include "clang/StaticAnalyzer/Core/Checker.h" 00023 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 00024 #include "llvm/ADT/BitVector.h" 00025 #include "llvm/ADT/SmallString.h" 00026 #include "llvm/Support/SaveAndRestore.h" 00027 00028 using namespace clang; 00029 using namespace ento; 00030 00031 namespace { 00032 00033 /// A simple visitor to record what VarDecls occur in EH-handling code. 00034 class EHCodeVisitor : public RecursiveASTVisitor<EHCodeVisitor> { 00035 public: 00036 bool inEH; 00037 llvm::DenseSet<const VarDecl *> &S; 00038 00039 bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { 00040 SaveAndRestore<bool> inFinally(inEH, true); 00041 return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S); 00042 } 00043 00044 bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) { 00045 SaveAndRestore<bool> inCatch(inEH, true); 00046 return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S); 00047 } 00048 00049 bool TraverseCXXCatchStmt(CXXCatchStmt *S) { 00050 SaveAndRestore<bool> inCatch(inEH, true); 00051 return TraverseStmt(S->getHandlerBlock()); 00052 } 00053 00054 bool VisitDeclRefExpr(DeclRefExpr *DR) { 00055 if (inEH) 00056 if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl())) 00057 S.insert(D); 00058 return true; 00059 } 00060 00061 EHCodeVisitor(llvm::DenseSet<const VarDecl *> &S) : 00062 inEH(false), S(S) {} 00063 }; 00064 00065 // FIXME: Eventually migrate into its own file, and have it managed by 00066 // AnalysisManager. 00067 class ReachableCode { 00068 const CFG &cfg; 00069 llvm::BitVector reachable; 00070 public: 00071 ReachableCode(const CFG &cfg) 00072 : cfg(cfg), reachable(cfg.getNumBlockIDs(), false) {} 00073 00074 void computeReachableBlocks(); 00075 00076 bool isReachable(const CFGBlock *block) const { 00077 return reachable[block->getBlockID()]; 00078 } 00079 }; 00080 } 00081 00082 void ReachableCode::computeReachableBlocks() { 00083 if (!cfg.getNumBlockIDs()) 00084 return; 00085 00086 SmallVector<const CFGBlock*, 10> worklist; 00087 worklist.push_back(&cfg.getEntry()); 00088 00089 while (!worklist.empty()) { 00090 const CFGBlock *block = worklist.pop_back_val(); 00091 llvm::BitVector::reference isReachable = reachable[block->getBlockID()]; 00092 if (isReachable) 00093 continue; 00094 isReachable = true; 00095 for (CFGBlock::const_succ_iterator i = block->succ_begin(), 00096 e = block->succ_end(); i != e; ++i) 00097 if (const CFGBlock *succ = *i) 00098 worklist.push_back(succ); 00099 } 00100 } 00101 00102 static const Expr * 00103 LookThroughTransitiveAssignmentsAndCommaOperators(const Expr *Ex) { 00104 while (Ex) { 00105 const BinaryOperator *BO = 00106 dyn_cast<BinaryOperator>(Ex->IgnoreParenCasts()); 00107 if (!BO) 00108 break; 00109 if (BO->getOpcode() == BO_Assign) { 00110 Ex = BO->getRHS(); 00111 continue; 00112 } 00113 if (BO->getOpcode() == BO_Comma) { 00114 Ex = BO->getRHS(); 00115 continue; 00116 } 00117 break; 00118 } 00119 return Ex; 00120 } 00121 00122 namespace { 00123 class DeadStoreObs : public LiveVariables::Observer { 00124 const CFG &cfg; 00125 ASTContext &Ctx; 00126 BugReporter& BR; 00127 const CheckerBase *Checker; 00128 AnalysisDeclContext* AC; 00129 ParentMap& Parents; 00130 llvm::SmallPtrSet<const VarDecl*, 20> Escaped; 00131 std::unique_ptr<ReachableCode> reachableCode; 00132 const CFGBlock *currentBlock; 00133 std::unique_ptr<llvm::DenseSet<const VarDecl *>> InEH; 00134 00135 enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit }; 00136 00137 public: 00138 DeadStoreObs(const CFG &cfg, ASTContext &ctx, BugReporter &br, 00139 const CheckerBase *checker, AnalysisDeclContext *ac, 00140 ParentMap &parents, 00141 llvm::SmallPtrSet<const VarDecl *, 20> &escaped) 00142 : cfg(cfg), Ctx(ctx), BR(br), Checker(checker), AC(ac), Parents(parents), 00143 Escaped(escaped), currentBlock(nullptr) {} 00144 00145 virtual ~DeadStoreObs() {} 00146 00147 bool isLive(const LiveVariables::LivenessValues &Live, const VarDecl *D) { 00148 if (Live.isLive(D)) 00149 return true; 00150 // Lazily construct the set that records which VarDecls are in 00151 // EH code. 00152 if (!InEH.get()) { 00153 InEH.reset(new llvm::DenseSet<const VarDecl *>()); 00154 EHCodeVisitor V(*InEH.get()); 00155 V.TraverseStmt(AC->getBody()); 00156 } 00157 // Treat all VarDecls that occur in EH code as being "always live" 00158 // when considering to suppress dead stores. Frequently stores 00159 // are followed by reads in EH code, but we don't have the ability 00160 // to analyze that yet. 00161 return InEH->count(D); 00162 } 00163 00164 void Report(const VarDecl *V, DeadStoreKind dsk, 00165 PathDiagnosticLocation L, SourceRange R) { 00166 if (Escaped.count(V)) 00167 return; 00168 00169 // Compute reachable blocks within the CFG for trivial cases 00170 // where a bogus dead store can be reported because itself is unreachable. 00171 if (!reachableCode.get()) { 00172 reachableCode.reset(new ReachableCode(cfg)); 00173 reachableCode->computeReachableBlocks(); 00174 } 00175 00176 if (!reachableCode->isReachable(currentBlock)) 00177 return; 00178 00179 SmallString<64> buf; 00180 llvm::raw_svector_ostream os(buf); 00181 const char *BugType = nullptr; 00182 00183 switch (dsk) { 00184 case DeadInit: 00185 BugType = "Dead initialization"; 00186 os << "Value stored to '" << *V 00187 << "' during its initialization is never read"; 00188 break; 00189 00190 case DeadIncrement: 00191 BugType = "Dead increment"; 00192 case Standard: 00193 if (!BugType) BugType = "Dead assignment"; 00194 os << "Value stored to '" << *V << "' is never read"; 00195 break; 00196 00197 case Enclosing: 00198 // Don't report issues in this case, e.g.: "if (x = foo())", 00199 // where 'x' is unused later. We have yet to see a case where 00200 // this is a real bug. 00201 return; 00202 } 00203 00204 BR.EmitBasicReport(AC->getDecl(), Checker, BugType, "Dead store", os.str(), 00205 L, R); 00206 } 00207 00208 void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val, 00209 DeadStoreKind dsk, 00210 const LiveVariables::LivenessValues &Live) { 00211 00212 if (!VD->hasLocalStorage()) 00213 return; 00214 // Reference types confuse the dead stores checker. Skip them 00215 // for now. 00216 if (VD->getType()->getAs<ReferenceType>()) 00217 return; 00218 00219 if (!isLive(Live, VD) && 00220 !(VD->hasAttr<UnusedAttr>() || VD->hasAttr<BlocksAttr>() || 00221 VD->hasAttr<ObjCPreciseLifetimeAttr>())) { 00222 00223 PathDiagnosticLocation ExLoc = 00224 PathDiagnosticLocation::createBegin(Ex, BR.getSourceManager(), AC); 00225 Report(VD, dsk, ExLoc, Val->getSourceRange()); 00226 } 00227 } 00228 00229 void CheckDeclRef(const DeclRefExpr *DR, const Expr *Val, DeadStoreKind dsk, 00230 const LiveVariables::LivenessValues& Live) { 00231 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) 00232 CheckVarDecl(VD, DR, Val, dsk, Live); 00233 } 00234 00235 bool isIncrement(VarDecl *VD, const BinaryOperator* B) { 00236 if (B->isCompoundAssignmentOp()) 00237 return true; 00238 00239 const Expr *RHS = B->getRHS()->IgnoreParenCasts(); 00240 const BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS); 00241 00242 if (!BRHS) 00243 return false; 00244 00245 const DeclRefExpr *DR; 00246 00247 if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts()))) 00248 if (DR->getDecl() == VD) 00249 return true; 00250 00251 if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts()))) 00252 if (DR->getDecl() == VD) 00253 return true; 00254 00255 return false; 00256 } 00257 00258 void observeStmt(const Stmt *S, const CFGBlock *block, 00259 const LiveVariables::LivenessValues &Live) override { 00260 00261 currentBlock = block; 00262 00263 // Skip statements in macros. 00264 if (S->getLocStart().isMacroID()) 00265 return; 00266 00267 // Only cover dead stores from regular assignments. ++/-- dead stores 00268 // have never flagged a real bug. 00269 if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) { 00270 if (!B->isAssignmentOp()) return; // Skip non-assignments. 00271 00272 if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS())) 00273 if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 00274 // Special case: check for assigning null to a pointer. 00275 // This is a common form of defensive programming. 00276 const Expr *RHS = 00277 LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS()); 00278 RHS = RHS->IgnoreParenCasts(); 00279 00280 QualType T = VD->getType(); 00281 if (T->isPointerType() || T->isObjCObjectPointerType()) { 00282 if (RHS->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull)) 00283 return; 00284 } 00285 00286 // Special case: self-assignments. These are often used to shut up 00287 // "unused variable" compiler warnings. 00288 if (const DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS)) 00289 if (VD == dyn_cast<VarDecl>(RhsDR->getDecl())) 00290 return; 00291 00292 // Otherwise, issue a warning. 00293 DeadStoreKind dsk = Parents.isConsumedExpr(B) 00294 ? Enclosing 00295 : (isIncrement(VD,B) ? DeadIncrement : Standard); 00296 00297 CheckVarDecl(VD, DR, B->getRHS(), dsk, Live); 00298 } 00299 } 00300 else if (const UnaryOperator* U = dyn_cast<UnaryOperator>(S)) { 00301 if (!U->isIncrementOp() || U->isPrefix()) 00302 return; 00303 00304 const Stmt *parent = Parents.getParentIgnoreParenCasts(U); 00305 if (!parent || !isa<ReturnStmt>(parent)) 00306 return; 00307 00308 const Expr *Ex = U->getSubExpr()->IgnoreParenCasts(); 00309 00310 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) 00311 CheckDeclRef(DR, U, DeadIncrement, Live); 00312 } 00313 else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) 00314 // Iterate through the decls. Warn if any initializers are complex 00315 // expressions that are not live (never used). 00316 for (const auto *DI : DS->decls()) { 00317 const auto *V = dyn_cast<VarDecl>(DI); 00318 00319 if (!V) 00320 continue; 00321 00322 if (V->hasLocalStorage()) { 00323 // Reference types confuse the dead stores checker. Skip them 00324 // for now. 00325 if (V->getType()->getAs<ReferenceType>()) 00326 return; 00327 00328 if (const Expr *E = V->getInit()) { 00329 while (const ExprWithCleanups *exprClean = 00330 dyn_cast<ExprWithCleanups>(E)) 00331 E = exprClean->getSubExpr(); 00332 00333 // Look through transitive assignments, e.g.: 00334 // int x = y = 0; 00335 E = LookThroughTransitiveAssignmentsAndCommaOperators(E); 00336 00337 // Don't warn on C++ objects (yet) until we can show that their 00338 // constructors/destructors don't have side effects. 00339 if (isa<CXXConstructExpr>(E)) 00340 return; 00341 00342 // A dead initialization is a variable that is dead after it 00343 // is initialized. We don't flag warnings for those variables 00344 // marked 'unused' or 'objc_precise_lifetime'. 00345 if (!isLive(Live, V) && 00346 !V->hasAttr<UnusedAttr>() && 00347 !V->hasAttr<ObjCPreciseLifetimeAttr>()) { 00348 // Special case: check for initializations with constants. 00349 // 00350 // e.g. : int x = 0; 00351 // 00352 // If x is EVER assigned a new value later, don't issue 00353 // a warning. This is because such initialization can be 00354 // due to defensive programming. 00355 if (E->isEvaluatable(Ctx)) 00356 return; 00357 00358 if (const DeclRefExpr *DRE = 00359 dyn_cast<DeclRefExpr>(E->IgnoreParenCasts())) 00360 if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { 00361 // Special case: check for initialization from constant 00362 // variables. 00363 // 00364 // e.g. extern const int MyConstant; 00365 // int x = MyConstant; 00366 // 00367 if (VD->hasGlobalStorage() && 00368 VD->getType().isConstQualified()) 00369 return; 00370 // Special case: check for initialization from scalar 00371 // parameters. This is often a form of defensive 00372 // programming. Non-scalars are still an error since 00373 // because it more likely represents an actual algorithmic 00374 // bug. 00375 if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType()) 00376 return; 00377 } 00378 00379 PathDiagnosticLocation Loc = 00380 PathDiagnosticLocation::create(V, BR.getSourceManager()); 00381 Report(V, DeadInit, Loc, E->getSourceRange()); 00382 } 00383 } 00384 } 00385 } 00386 } 00387 }; 00388 00389 } // end anonymous namespace 00390 00391 //===----------------------------------------------------------------------===// 00392 // Driver function to invoke the Dead-Stores checker on a CFG. 00393 //===----------------------------------------------------------------------===// 00394 00395 namespace { 00396 class FindEscaped { 00397 public: 00398 llvm::SmallPtrSet<const VarDecl*, 20> Escaped; 00399 00400 void operator()(const Stmt *S) { 00401 // Check for '&'. Any VarDecl whose address has been taken we treat as 00402 // escaped. 00403 // FIXME: What about references? 00404 const UnaryOperator *U = dyn_cast<UnaryOperator>(S); 00405 if (!U) 00406 return; 00407 if (U->getOpcode() != UO_AddrOf) 00408 return; 00409 00410 const Expr *E = U->getSubExpr()->IgnoreParenCasts(); 00411 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) 00412 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) 00413 Escaped.insert(VD); 00414 } 00415 }; 00416 } // end anonymous namespace 00417 00418 00419 //===----------------------------------------------------------------------===// 00420 // DeadStoresChecker 00421 //===----------------------------------------------------------------------===// 00422 00423 namespace { 00424 class DeadStoresChecker : public Checker<check::ASTCodeBody> { 00425 public: 00426 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 00427 BugReporter &BR) const { 00428 00429 // Don't do anything for template instantiations. 00430 // Proving that code in a template instantiation is "dead" 00431 // means proving that it is dead in all instantiations. 00432 // This same problem exists with -Wunreachable-code. 00433 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) 00434 if (FD->isTemplateInstantiation()) 00435 return; 00436 00437 if (LiveVariables *L = mgr.getAnalysis<LiveVariables>(D)) { 00438 CFG &cfg = *mgr.getCFG(D); 00439 AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D); 00440 ParentMap &pmap = mgr.getParentMap(D); 00441 FindEscaped FS; 00442 cfg.VisitBlockStmts(FS); 00443 DeadStoreObs A(cfg, BR.getContext(), BR, this, AC, pmap, FS.Escaped); 00444 L->runOnAllBlocks(A); 00445 } 00446 } 00447 }; 00448 } 00449 00450 void ento::registerDeadStoresChecker(CheckerManager &mgr) { 00451 mgr.registerChecker<DeadStoresChecker>(); 00452 }