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/StaticAnalyzer/Core/Checker.h" 00017 #include "clang/Analysis/Analyses/LiveVariables.h" 00018 #include "clang/Analysis/Visitors/CFGRecStmtVisitor.h" 00019 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 00020 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 00021 #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" 00022 #include "clang/Basic/Diagnostic.h" 00023 #include "clang/AST/ASTContext.h" 00024 #include "clang/AST/ParentMap.h" 00025 #include "llvm/ADT/SmallPtrSet.h" 00026 #include "llvm/ADT/SmallString.h" 00027 00028 using namespace clang; 00029 using namespace ento; 00030 00031 namespace { 00032 00033 // FIXME: Eventually migrate into its own file, and have it managed by 00034 // AnalysisManager. 00035 class ReachableCode { 00036 const CFG &cfg; 00037 llvm::BitVector reachable; 00038 public: 00039 ReachableCode(const CFG &cfg) 00040 : cfg(cfg), reachable(cfg.getNumBlockIDs(), false) {} 00041 00042 void computeReachableBlocks(); 00043 00044 bool isReachable(const CFGBlock *block) const { 00045 return reachable[block->getBlockID()]; 00046 } 00047 }; 00048 } 00049 00050 void ReachableCode::computeReachableBlocks() { 00051 if (!cfg.getNumBlockIDs()) 00052 return; 00053 00054 SmallVector<const CFGBlock*, 10> worklist; 00055 worklist.push_back(&cfg.getEntry()); 00056 00057 while (!worklist.empty()) { 00058 const CFGBlock *block = worklist.back(); 00059 worklist.pop_back(); 00060 llvm::BitVector::reference isReachable = reachable[block->getBlockID()]; 00061 if (isReachable) 00062 continue; 00063 isReachable = true; 00064 for (CFGBlock::const_succ_iterator i = block->succ_begin(), 00065 e = block->succ_end(); i != e; ++i) 00066 if (const CFGBlock *succ = *i) 00067 worklist.push_back(succ); 00068 } 00069 } 00070 00071 static const Expr *LookThroughTransitiveAssignments(const Expr *Ex) { 00072 while (Ex) { 00073 const BinaryOperator *BO = 00074 dyn_cast<BinaryOperator>(Ex->IgnoreParenCasts()); 00075 if (!BO) 00076 break; 00077 if (BO->getOpcode() == BO_Assign) { 00078 Ex = BO->getRHS(); 00079 continue; 00080 } 00081 break; 00082 } 00083 return Ex; 00084 } 00085 00086 namespace { 00087 class DeadStoreObs : public LiveVariables::Observer { 00088 const CFG &cfg; 00089 ASTContext &Ctx; 00090 BugReporter& BR; 00091 AnalysisDeclContext* AC; 00092 ParentMap& Parents; 00093 llvm::SmallPtrSet<const VarDecl*, 20> Escaped; 00094 OwningPtr<ReachableCode> reachableCode; 00095 const CFGBlock *currentBlock; 00096 00097 enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit }; 00098 00099 public: 00100 DeadStoreObs(const CFG &cfg, ASTContext &ctx, 00101 BugReporter& br, AnalysisDeclContext* ac, ParentMap& parents, 00102 llvm::SmallPtrSet<const VarDecl*, 20> &escaped) 00103 : cfg(cfg), Ctx(ctx), BR(br), AC(ac), Parents(parents), 00104 Escaped(escaped), currentBlock(0) {} 00105 00106 virtual ~DeadStoreObs() {} 00107 00108 void Report(const VarDecl *V, DeadStoreKind dsk, 00109 PathDiagnosticLocation L, SourceRange R) { 00110 if (Escaped.count(V)) 00111 return; 00112 00113 // Compute reachable blocks within the CFG for trivial cases 00114 // where a bogus dead store can be reported because itself is unreachable. 00115 if (!reachableCode.get()) { 00116 reachableCode.reset(new ReachableCode(cfg)); 00117 reachableCode->computeReachableBlocks(); 00118 } 00119 00120 if (!reachableCode->isReachable(currentBlock)) 00121 return; 00122 00123 SmallString<64> buf; 00124 llvm::raw_svector_ostream os(buf); 00125 const char *BugType = 0; 00126 00127 switch (dsk) { 00128 case DeadInit: 00129 BugType = "Dead initialization"; 00130 os << "Value stored to '" << *V 00131 << "' during its initialization is never read"; 00132 break; 00133 00134 case DeadIncrement: 00135 BugType = "Dead increment"; 00136 case Standard: 00137 if (!BugType) BugType = "Dead assignment"; 00138 os << "Value stored to '" << *V << "' is never read"; 00139 break; 00140 00141 case Enclosing: 00142 // Don't report issues in this case, e.g.: "if (x = foo())", 00143 // where 'x' is unused later. We have yet to see a case where 00144 // this is a real bug. 00145 return; 00146 } 00147 00148 BR.EmitBasicReport(AC->getDecl(), BugType, "Dead store", os.str(), L, R); 00149 } 00150 00151 void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val, 00152 DeadStoreKind dsk, 00153 const LiveVariables::LivenessValues &Live) { 00154 00155 if (!VD->hasLocalStorage()) 00156 return; 00157 // Reference types confuse the dead stores checker. Skip them 00158 // for now. 00159 if (VD->getType()->getAs<ReferenceType>()) 00160 return; 00161 00162 if (!Live.isLive(VD) && 00163 !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) { 00164 00165 PathDiagnosticLocation ExLoc = 00166 PathDiagnosticLocation::createBegin(Ex, BR.getSourceManager(), AC); 00167 Report(VD, dsk, ExLoc, Val->getSourceRange()); 00168 } 00169 } 00170 00171 void CheckDeclRef(const DeclRefExpr *DR, const Expr *Val, DeadStoreKind dsk, 00172 const LiveVariables::LivenessValues& Live) { 00173 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) 00174 CheckVarDecl(VD, DR, Val, dsk, Live); 00175 } 00176 00177 bool isIncrement(VarDecl *VD, const BinaryOperator* B) { 00178 if (B->isCompoundAssignmentOp()) 00179 return true; 00180 00181 const Expr *RHS = B->getRHS()->IgnoreParenCasts(); 00182 const BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS); 00183 00184 if (!BRHS) 00185 return false; 00186 00187 const DeclRefExpr *DR; 00188 00189 if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts()))) 00190 if (DR->getDecl() == VD) 00191 return true; 00192 00193 if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts()))) 00194 if (DR->getDecl() == VD) 00195 return true; 00196 00197 return false; 00198 } 00199 00200 virtual void observeStmt(const Stmt *S, const CFGBlock *block, 00201 const LiveVariables::LivenessValues &Live) { 00202 00203 currentBlock = block; 00204 00205 // Skip statements in macros. 00206 if (S->getLocStart().isMacroID()) 00207 return; 00208 00209 // Only cover dead stores from regular assignments. ++/-- dead stores 00210 // have never flagged a real bug. 00211 if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) { 00212 if (!B->isAssignmentOp()) return; // Skip non-assignments. 00213 00214 if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS())) 00215 if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 00216 // Special case: check for assigning null to a pointer. 00217 // This is a common form of defensive programming. 00218 const Expr *RHS = LookThroughTransitiveAssignments(B->getRHS()); 00219 00220 QualType T = VD->getType(); 00221 if (T->isPointerType() || T->isObjCObjectPointerType()) { 00222 if (RHS->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull)) 00223 return; 00224 } 00225 00226 RHS = RHS->IgnoreParenCasts(); 00227 // Special case: self-assignments. These are often used to shut up 00228 // "unused variable" compiler warnings. 00229 if (const DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS)) 00230 if (VD == dyn_cast<VarDecl>(RhsDR->getDecl())) 00231 return; 00232 00233 // Otherwise, issue a warning. 00234 DeadStoreKind dsk = Parents.isConsumedExpr(B) 00235 ? Enclosing 00236 : (isIncrement(VD,B) ? DeadIncrement : Standard); 00237 00238 CheckVarDecl(VD, DR, B->getRHS(), dsk, Live); 00239 } 00240 } 00241 else if (const UnaryOperator* U = dyn_cast<UnaryOperator>(S)) { 00242 if (!U->isIncrementOp() || U->isPrefix()) 00243 return; 00244 00245 const Stmt *parent = Parents.getParentIgnoreParenCasts(U); 00246 if (!parent || !isa<ReturnStmt>(parent)) 00247 return; 00248 00249 const Expr *Ex = U->getSubExpr()->IgnoreParenCasts(); 00250 00251 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) 00252 CheckDeclRef(DR, U, DeadIncrement, Live); 00253 } 00254 else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) 00255 // Iterate through the decls. Warn if any initializers are complex 00256 // expressions that are not live (never used). 00257 for (DeclStmt::const_decl_iterator DI=DS->decl_begin(), DE=DS->decl_end(); 00258 DI != DE; ++DI) { 00259 00260 VarDecl *V = dyn_cast<VarDecl>(*DI); 00261 00262 if (!V) 00263 continue; 00264 00265 if (V->hasLocalStorage()) { 00266 // Reference types confuse the dead stores checker. Skip them 00267 // for now. 00268 if (V->getType()->getAs<ReferenceType>()) 00269 return; 00270 00271 if (const Expr *E = V->getInit()) { 00272 while (const ExprWithCleanups *exprClean = 00273 dyn_cast<ExprWithCleanups>(E)) 00274 E = exprClean->getSubExpr(); 00275 00276 // Look through transitive assignments, e.g.: 00277 // int x = y = 0; 00278 E = LookThroughTransitiveAssignments(E); 00279 00280 // Don't warn on C++ objects (yet) until we can show that their 00281 // constructors/destructors don't have side effects. 00282 if (isa<CXXConstructExpr>(E)) 00283 return; 00284 00285 // A dead initialization is a variable that is dead after it 00286 // is initialized. We don't flag warnings for those variables 00287 // marked 'unused'. 00288 if (!Live.isLive(V) && V->getAttr<UnusedAttr>() == 0) { 00289 // Special case: check for initializations with constants. 00290 // 00291 // e.g. : int x = 0; 00292 // 00293 // If x is EVER assigned a new value later, don't issue 00294 // a warning. This is because such initialization can be 00295 // due to defensive programming. 00296 if (E->isEvaluatable(Ctx)) 00297 return; 00298 00299 if (const DeclRefExpr *DRE = 00300 dyn_cast<DeclRefExpr>(E->IgnoreParenCasts())) 00301 if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { 00302 // Special case: check for initialization from constant 00303 // variables. 00304 // 00305 // e.g. extern const int MyConstant; 00306 // int x = MyConstant; 00307 // 00308 if (VD->hasGlobalStorage() && 00309 VD->getType().isConstQualified()) 00310 return; 00311 // Special case: check for initialization from scalar 00312 // parameters. This is often a form of defensive 00313 // programming. Non-scalars are still an error since 00314 // because it more likely represents an actual algorithmic 00315 // bug. 00316 if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType()) 00317 return; 00318 } 00319 00320 PathDiagnosticLocation Loc = 00321 PathDiagnosticLocation::create(V, BR.getSourceManager()); 00322 Report(V, DeadInit, Loc, E->getSourceRange()); 00323 } 00324 } 00325 } 00326 } 00327 } 00328 }; 00329 00330 } // end anonymous namespace 00331 00332 //===----------------------------------------------------------------------===// 00333 // Driver function to invoke the Dead-Stores checker on a CFG. 00334 //===----------------------------------------------------------------------===// 00335 00336 namespace { 00337 class FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{ 00338 CFG *cfg; 00339 public: 00340 FindEscaped(CFG *c) : cfg(c) {} 00341 00342 CFG& getCFG() { return *cfg; } 00343 00344 llvm::SmallPtrSet<const VarDecl*, 20> Escaped; 00345 00346 void VisitUnaryOperator(UnaryOperator* U) { 00347 // Check for '&'. Any VarDecl whose value has its address-taken we 00348 // treat as escaped. 00349 Expr *E = U->getSubExpr()->IgnoreParenCasts(); 00350 if (U->getOpcode() == UO_AddrOf) 00351 if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) 00352 if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 00353 Escaped.insert(VD); 00354 return; 00355 } 00356 Visit(E); 00357 } 00358 }; 00359 } // end anonymous namespace 00360 00361 00362 //===----------------------------------------------------------------------===// 00363 // DeadStoresChecker 00364 //===----------------------------------------------------------------------===// 00365 00366 namespace { 00367 class DeadStoresChecker : public Checker<check::ASTCodeBody> { 00368 public: 00369 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 00370 BugReporter &BR) const { 00371 if (LiveVariables *L = mgr.getAnalysis<LiveVariables>(D)) { 00372 CFG &cfg = *mgr.getCFG(D); 00373 AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D); 00374 ParentMap &pmap = mgr.getParentMap(D); 00375 FindEscaped FS(&cfg); 00376 FS.getCFG().VisitBlockStmts(FS); 00377 DeadStoreObs A(cfg, BR.getContext(), BR, AC, pmap, FS.Escaped); 00378 L->runOnAllBlocks(A); 00379 } 00380 } 00381 }; 00382 } 00383 00384 void ento::registerDeadStoresChecker(CheckerManager &mgr) { 00385 mgr.registerChecker<DeadStoresChecker>(); 00386 }