]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / UnreachableCodeChecker.cpp
1 //==- UnreachableCodeChecker.cpp - Generalized dead code checker -*- C++ -*-==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 // This file implements a generalized unreachable code checker using a
10 // path-sensitive analysis. We mark any path visited, and then walk the CFG as a
11 // post-analysis to determine what was never visited.
12 //
13 // A similar flow-sensitive only check exists in Analysis/ReachableCode.cpp
14 //===----------------------------------------------------------------------===//
15
16 #include "ClangSACheckers.h"
17 #include "clang/StaticAnalyzer/Core/Checker.h"
18 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
23 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
24 #include "clang/AST/ParentMap.h"
25 #include "clang/Basic/Builtins.h"
26 #include "clang/Basic/SourceManager.h"
27 #include "llvm/ADT/SmallPtrSet.h"
28
29 // The number of CFGBlock pointers we want to reserve memory for. This is used
30 // once for each function we analyze.
31 #define DEFAULT_CFGBLOCKS 256
32
33 using namespace clang;
34 using namespace ento;
35
36 namespace {
37 class UnreachableCodeChecker : public Checker<check::EndAnalysis> {
38 public:
39   void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,
40                         ExprEngine &Eng) const;
41 private:
42   typedef llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> CFGBlocksSet;
43
44   static inline const Stmt *getUnreachableStmt(const CFGBlock *CB);
45   static void FindUnreachableEntryPoints(const CFGBlock *CB,
46                                          CFGBlocksSet &reachable,
47                                          CFGBlocksSet &visited);
48   static bool isInvalidPath(const CFGBlock *CB, const ParentMap &PM);
49   static inline bool isEmptyCFGBlock(const CFGBlock *CB);
50 };
51 }
52
53 void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
54                                               BugReporter &B,
55                                               ExprEngine &Eng) const {
56   CFGBlocksSet reachable, visited;
57
58   if (Eng.hasWorkRemaining())
59     return;
60
61   CFG *C = 0;
62   ParentMap *PM = 0;
63   const LocationContext *LC = 0;
64   // Iterate over ExplodedGraph
65   for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end();
66       I != E; ++I) {
67     const ProgramPoint &P = I->getLocation();
68     LC = P.getLocationContext();
69
70     // Save the CFG if we don't have it already
71     if (!C)
72       C = LC->getAnalysisContext()->getUnoptimizedCFG();
73     if (!PM)
74       PM = &LC->getParentMap();
75
76     if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
77       const CFGBlock *CB = BE->getBlock();
78       reachable.insert(CB->getBlockID());
79     }
80   }
81
82   // Bail out if we didn't get the CFG or the ParentMap.
83   if (!C || !PM)
84     return;
85
86   ASTContext &Ctx = B.getContext();
87
88   // Find CFGBlocks that were not covered by any node
89   for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) {
90     const CFGBlock *CB = *I;
91     // Check if the block is unreachable
92     if (reachable.count(CB->getBlockID()))
93       continue;
94
95     // Check if the block is empty (an artificial block)
96     if (isEmptyCFGBlock(CB))
97       continue;
98
99     // Find the entry points for this block
100     if (!visited.count(CB->getBlockID()))
101       FindUnreachableEntryPoints(CB, reachable, visited);
102
103     // This block may have been pruned; check if we still want to report it
104     if (reachable.count(CB->getBlockID()))
105       continue;
106
107     // Check for false positives
108     if (CB->size() > 0 && isInvalidPath(CB, *PM))
109       continue;
110
111     // Special case for __builtin_unreachable.
112     // FIXME: This should be extended to include other unreachable markers,
113     // such as llvm_unreachable.
114     if (!CB->empty()) {
115       bool foundUnreachable = false;
116       for (CFGBlock::const_iterator ci = CB->begin(), ce = CB->end();
117            ci != ce; ++ci) {
118         if (const CFGStmt *S = (*ci).getAs<CFGStmt>())
119           if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
120             if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable) {
121               foundUnreachable = true;
122               break;
123             }
124           }
125       }
126       if (foundUnreachable)
127         continue;
128     }
129
130     // We found a block that wasn't covered - find the statement to report
131     SourceRange SR;
132     PathDiagnosticLocation DL;
133     SourceLocation SL;
134     if (const Stmt *S = getUnreachableStmt(CB)) {
135       SR = S->getSourceRange();
136       DL = PathDiagnosticLocation::createBegin(S, B.getSourceManager(), LC);
137       SL = DL.asLocation();
138       if (SR.isInvalid() || !SL.isValid())
139         continue;
140     }
141     else
142       continue;
143
144     // Check if the SourceLocation is in a system header
145     const SourceManager &SM = B.getSourceManager();
146     if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL))
147       continue;
148
149     B.EmitBasicReport("Unreachable code", "Dead code", "This statement is never"
150         " executed", DL, SR);
151   }
152 }
153
154 // Recursively finds the entry point(s) for this dead CFGBlock.
155 void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB,
156                                                         CFGBlocksSet &reachable,
157                                                         CFGBlocksSet &visited) {
158   visited.insert(CB->getBlockID());
159
160   for (CFGBlock::const_pred_iterator I = CB->pred_begin(), E = CB->pred_end();
161       I != E; ++I) {
162     if (!reachable.count((*I)->getBlockID())) {
163       // If we find an unreachable predecessor, mark this block as reachable so
164       // we don't report this block
165       reachable.insert(CB->getBlockID());
166       if (!visited.count((*I)->getBlockID()))
167         // If we haven't previously visited the unreachable predecessor, recurse
168         FindUnreachableEntryPoints(*I, reachable, visited);
169     }
170   }
171 }
172
173 // Find the Stmt* in a CFGBlock for reporting a warning
174 const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) {
175   for (CFGBlock::const_iterator I = CB->begin(), E = CB->end(); I != E; ++I) {
176     if (const CFGStmt *S = I->getAs<CFGStmt>())
177       return S->getStmt();
178   }
179   if (const Stmt *S = CB->getTerminator())
180     return S;
181   else
182     return 0;
183 }
184
185 // Determines if the path to this CFGBlock contained an element that infers this
186 // block is a false positive. We assume that FindUnreachableEntryPoints has
187 // already marked only the entry points to any dead code, so we need only to
188 // find the condition that led to this block (the predecessor of this block.)
189 // There will never be more than one predecessor.
190 bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB,
191                                            const ParentMap &PM) {
192   // We only expect a predecessor size of 0 or 1. If it is >1, then an external
193   // condition has broken our assumption (for example, a sink being placed by
194   // another check). In these cases, we choose not to report.
195   if (CB->pred_size() > 1)
196     return true;
197
198   // If there are no predecessors, then this block is trivially unreachable
199   if (CB->pred_size() == 0)
200     return false;
201
202   const CFGBlock *pred = *CB->pred_begin();
203
204   // Get the predecessor block's terminator conditon
205   const Stmt *cond = pred->getTerminatorCondition();
206
207   //assert(cond && "CFGBlock's predecessor has a terminator condition");
208   // The previous assertion is invalid in some cases (eg do/while). Leaving
209   // reporting of these situations on at the moment to help triage these cases.
210   if (!cond)
211     return false;
212
213   // Run each of the checks on the conditions
214   if (containsMacro(cond) || containsEnum(cond)
215       || containsStaticLocal(cond) || containsBuiltinOffsetOf(cond)
216       || containsStmt<UnaryExprOrTypeTraitExpr>(cond))
217     return true;
218
219   return false;
220 }
221
222 // Returns true if the given CFGBlock is empty
223 bool UnreachableCodeChecker::isEmptyCFGBlock(const CFGBlock *CB) {
224   return CB->getLabel() == 0       // No labels
225       && CB->size() == 0           // No statements
226       && CB->getTerminator() == 0; // No terminator
227 }
228
229 void ento::registerUnreachableCodeChecker(CheckerManager &mgr) {
230   mgr.registerChecker<UnreachableCodeChecker>();
231 }