clang API Documentation

UnreachableCodeChecker.cpp
Go to the documentation of this file.
00001 //==- UnreachableCodeChecker.cpp - Generalized dead code checker -*- 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 // This file implements a generalized unreachable code checker using a
00010 // path-sensitive analysis. We mark any path visited, and then walk the CFG as a
00011 // post-analysis to determine what was never visited.
00012 //
00013 // A similar flow-sensitive only check exists in Analysis/ReachableCode.cpp
00014 //===----------------------------------------------------------------------===//
00015 
00016 #include "ClangSACheckers.h"
00017 #include "clang/StaticAnalyzer/Core/Checker.h"
00018 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
00019 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
00020 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
00021 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
00022 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
00023 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
00024 #include "clang/AST/ParentMap.h"
00025 #include "clang/Basic/Builtins.h"
00026 #include "clang/Basic/SourceManager.h"
00027 #include "llvm/ADT/SmallSet.h"
00028 
00029 // The number of CFGBlock pointers we want to reserve memory for. This is used
00030 // once for each function we analyze.
00031 #define DEFAULT_CFGBLOCKS 256
00032 
00033 using namespace clang;
00034 using namespace ento;
00035 
00036 namespace {
00037 class UnreachableCodeChecker : public Checker<check::EndAnalysis> {
00038 public:
00039   void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,
00040                         ExprEngine &Eng) const;
00041 private:
00042   typedef llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> CFGBlocksSet;
00043 
00044   static inline const Stmt *getUnreachableStmt(const CFGBlock *CB);
00045   static void FindUnreachableEntryPoints(const CFGBlock *CB,
00046                                          CFGBlocksSet &reachable,
00047                                          CFGBlocksSet &visited);
00048   static bool isInvalidPath(const CFGBlock *CB, const ParentMap &PM);
00049   static inline bool isEmptyCFGBlock(const CFGBlock *CB);
00050 };
00051 }
00052 
00053 void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
00054                                               BugReporter &B,
00055                                               ExprEngine &Eng) const {
00056   CFGBlocksSet reachable, visited;
00057   
00058   if (Eng.hasWorkRemaining())
00059     return;
00060 
00061   const Decl *D = 0;
00062   CFG *C = 0;
00063   ParentMap *PM = 0;
00064   const LocationContext *LC = 0;
00065   // Iterate over ExplodedGraph
00066   for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end();
00067       I != E; ++I) {
00068     const ProgramPoint &P = I->getLocation();
00069     LC = P.getLocationContext();
00070 
00071     if (!D)
00072       D = LC->getAnalysisDeclContext()->getDecl();
00073     // Save the CFG if we don't have it already
00074     if (!C)
00075       C = LC->getAnalysisDeclContext()->getUnoptimizedCFG();
00076     if (!PM)
00077       PM = &LC->getParentMap();
00078 
00079     if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
00080       const CFGBlock *CB = BE->getBlock();
00081       reachable.insert(CB->getBlockID());
00082     }
00083   }
00084 
00085   // Bail out if we didn't get the CFG or the ParentMap.
00086   if (!D || !C || !PM)
00087     return;
00088   
00089   // Don't do anything for template instantiations.  Proving that code
00090   // in a template instantiation is unreachable means proving that it is
00091   // unreachable in all instantiations.
00092   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
00093     if (FD->isTemplateInstantiation())
00094       return;
00095 
00096   // Find CFGBlocks that were not covered by any node
00097   for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) {
00098     const CFGBlock *CB = *I;
00099     // Check if the block is unreachable
00100     if (reachable.count(CB->getBlockID()))
00101       continue;
00102 
00103     // Check if the block is empty (an artificial block)
00104     if (isEmptyCFGBlock(CB))
00105       continue;
00106 
00107     // Find the entry points for this block
00108     if (!visited.count(CB->getBlockID()))
00109       FindUnreachableEntryPoints(CB, reachable, visited);
00110 
00111     // This block may have been pruned; check if we still want to report it
00112     if (reachable.count(CB->getBlockID()))
00113       continue;
00114 
00115     // Check for false positives
00116     if (CB->size() > 0 && isInvalidPath(CB, *PM))
00117       continue;
00118 
00119     // It is good practice to always have a "default" label in a "switch", even
00120     // if we should never get there. It can be used to detect errors, for
00121     // instance. Unreachable code directly under a "default" label is therefore
00122     // likely to be a false positive.
00123     if (const Stmt *label = CB->getLabel())
00124       if (label->getStmtClass() == Stmt::DefaultStmtClass)
00125         continue;
00126 
00127     // Special case for __builtin_unreachable.
00128     // FIXME: This should be extended to include other unreachable markers,
00129     // such as llvm_unreachable.
00130     if (!CB->empty()) {
00131       bool foundUnreachable = false;
00132       for (CFGBlock::const_iterator ci = CB->begin(), ce = CB->end();
00133            ci != ce; ++ci) {
00134         if (const CFGStmt *S = (*ci).getAs<CFGStmt>())
00135           if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
00136             if (CE->isBuiltinCall() == Builtin::BI__builtin_unreachable) {
00137               foundUnreachable = true;
00138               break;
00139             }
00140           }
00141       }
00142       if (foundUnreachable)
00143         continue;
00144     }
00145 
00146     // We found a block that wasn't covered - find the statement to report
00147     SourceRange SR;
00148     PathDiagnosticLocation DL;
00149     SourceLocation SL;
00150     if (const Stmt *S = getUnreachableStmt(CB)) {
00151       SR = S->getSourceRange();
00152       DL = PathDiagnosticLocation::createBegin(S, B.getSourceManager(), LC);
00153       SL = DL.asLocation();
00154       if (SR.isInvalid() || !SL.isValid())
00155         continue;
00156     }
00157     else
00158       continue;
00159 
00160     // Check if the SourceLocation is in a system header
00161     const SourceManager &SM = B.getSourceManager();
00162     if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL))
00163       continue;
00164 
00165     B.EmitBasicReport(D, "Unreachable code", "Dead code",
00166                       "This statement is never executed", DL, SR);
00167   }
00168 }
00169 
00170 // Recursively finds the entry point(s) for this dead CFGBlock.
00171 void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB,
00172                                                         CFGBlocksSet &reachable,
00173                                                         CFGBlocksSet &visited) {
00174   visited.insert(CB->getBlockID());
00175 
00176   for (CFGBlock::const_pred_iterator I = CB->pred_begin(), E = CB->pred_end();
00177       I != E; ++I) {
00178     if (!reachable.count((*I)->getBlockID())) {
00179       // If we find an unreachable predecessor, mark this block as reachable so
00180       // we don't report this block
00181       reachable.insert(CB->getBlockID());
00182       if (!visited.count((*I)->getBlockID()))
00183         // If we haven't previously visited the unreachable predecessor, recurse
00184         FindUnreachableEntryPoints(*I, reachable, visited);
00185     }
00186   }
00187 }
00188 
00189 // Find the Stmt* in a CFGBlock for reporting a warning
00190 const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) {
00191   for (CFGBlock::const_iterator I = CB->begin(), E = CB->end(); I != E; ++I) {
00192     if (const CFGStmt *S = I->getAs<CFGStmt>())
00193       return S->getStmt();
00194   }
00195   if (const Stmt *S = CB->getTerminator())
00196     return S;
00197   else
00198     return 0;
00199 }
00200 
00201 // Determines if the path to this CFGBlock contained an element that infers this
00202 // block is a false positive. We assume that FindUnreachableEntryPoints has
00203 // already marked only the entry points to any dead code, so we need only to
00204 // find the condition that led to this block (the predecessor of this block.)
00205 // There will never be more than one predecessor.
00206 bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB,
00207                                            const ParentMap &PM) {
00208   // We only expect a predecessor size of 0 or 1. If it is >1, then an external
00209   // condition has broken our assumption (for example, a sink being placed by
00210   // another check). In these cases, we choose not to report.
00211   if (CB->pred_size() > 1)
00212     return true;
00213 
00214   // If there are no predecessors, then this block is trivially unreachable
00215   if (CB->pred_size() == 0)
00216     return false;
00217 
00218   const CFGBlock *pred = *CB->pred_begin();
00219 
00220   // Get the predecessor block's terminator conditon
00221   const Stmt *cond = pred->getTerminatorCondition();
00222 
00223   //assert(cond && "CFGBlock's predecessor has a terminator condition");
00224   // The previous assertion is invalid in some cases (eg do/while). Leaving
00225   // reporting of these situations on at the moment to help triage these cases.
00226   if (!cond)
00227     return false;
00228 
00229   // Run each of the checks on the conditions
00230   if (containsMacro(cond) || containsEnum(cond)
00231       || containsStaticLocal(cond) || containsBuiltinOffsetOf(cond)
00232       || containsStmt<UnaryExprOrTypeTraitExpr>(cond))
00233     return true;
00234 
00235   return false;
00236 }
00237 
00238 // Returns true if the given CFGBlock is empty
00239 bool UnreachableCodeChecker::isEmptyCFGBlock(const CFGBlock *CB) {
00240   return CB->getLabel() == 0       // No labels
00241       && CB->size() == 0           // No statements
00242       && CB->getTerminator() == 0; // No terminator
00243 }
00244 
00245 void ento::registerUnreachableCodeChecker(CheckerManager &mgr) {
00246   mgr.registerChecker<UnreachableCodeChecker>();
00247 }