blob: a84a3a5603980549da0dd1f87d8de127573d0ddd [file] [log] [blame]
Tom Carec4b5bd82010-07-23 23:04:53 +00001//==- 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//
Jordy Rose5e04bdd2010-07-27 03:39:53 +000013// A similar flow-sensitive only check exists in Analysis/ReachableCode.cpp
Tom Carec4b5bd82010-07-23 23:04:53 +000014//===----------------------------------------------------------------------===//
15
Tom Care7bce3a12010-07-27 23:30:21 +000016#include "clang/AST/ParentMap.h"
17#include "clang/Basic/Builtins.h"
Tom Caref8906792010-08-03 21:24:13 +000018#include "clang/Basic/SourceManager.h"
Tom Carec4b5bd82010-07-23 23:04:53 +000019#include "clang/Checker/PathSensitive/CheckerVisitor.h"
20#include "clang/Checker/PathSensitive/ExplodedGraph.h"
21#include "clang/Checker/PathSensitive/SVals.h"
Tom Care7bce3a12010-07-27 23:30:21 +000022#include "clang/Checker/PathSensitive/CheckerHelpers.h"
Tom Carec4b5bd82010-07-23 23:04:53 +000023#include "clang/Checker/BugReporter/BugReporter.h"
24#include "GRExprEngineExperimentalChecks.h"
Tom Carec4b5bd82010-07-23 23:04:53 +000025#include "llvm/ADT/SmallPtrSet.h"
26
27// The number of CFGBlock pointers we want to reserve memory for. This is used
28// once for each function we analyze.
29#define DEFAULT_CFGBLOCKS 256
30
31using namespace clang;
32
33namespace {
34class UnreachableCodeChecker : public CheckerVisitor<UnreachableCodeChecker> {
35public:
36 static void *getTag();
Tom Carebc42c532010-08-03 01:55:07 +000037 void VisitEndAnalysis(ExplodedGraph &G,
38 BugReporter &B,
39 GRExprEngine &Eng);
Tom Carec4b5bd82010-07-23 23:04:53 +000040private:
Tom Caref8906792010-08-03 21:24:13 +000041 static inline const Stmt *getUnreachableStmt(const CFGBlock *CB);
Tom Carec4b5bd82010-07-23 23:04:53 +000042 void FindUnreachableEntryPoints(const CFGBlock *CB);
Tom Care7bce3a12010-07-27 23:30:21 +000043 static bool isInvalidPath(const CFGBlock *CB, const ParentMap &PM);
Tom Carec4b5bd82010-07-23 23:04:53 +000044
Tom Caref8906792010-08-03 21:24:13 +000045 llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> reachable;
46 llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> visited;
Tom Carec4b5bd82010-07-23 23:04:53 +000047};
48}
49
50void *UnreachableCodeChecker::getTag() {
51 static int x = 0;
52 return &x;
53}
54
55void clang::RegisterUnreachableCodeChecker(GRExprEngine &Eng) {
56 Eng.registerCheck(new UnreachableCodeChecker());
57}
58
59void UnreachableCodeChecker::VisitEndAnalysis(ExplodedGraph &G,
60 BugReporter &B,
Tom Carebc42c532010-08-03 01:55:07 +000061 GRExprEngine &Eng) {
Tom Carec4b5bd82010-07-23 23:04:53 +000062 // Bail out if we didn't cover all paths
Tom Carebc42c532010-08-03 01:55:07 +000063 if (Eng.hasWorkRemaining())
Tom Carec4b5bd82010-07-23 23:04:53 +000064 return;
65
66 CFG *C = 0;
Tom Care7bce3a12010-07-27 23:30:21 +000067 ParentMap *PM = 0;
Tom Carec4b5bd82010-07-23 23:04:53 +000068 // Iterate over ExplodedGraph
69 for (ExplodedGraph::node_iterator I = G.nodes_begin(); I != G.nodes_end();
70 ++I) {
71 const ProgramPoint &P = I->getLocation();
Tom Care7bce3a12010-07-27 23:30:21 +000072 const LocationContext *LC = P.getLocationContext();
Tom Carec4b5bd82010-07-23 23:04:53 +000073
74 // Save the CFG if we don't have it already
75 if (!C)
Tom Caref8906792010-08-03 21:24:13 +000076 C = LC->getAnalysisContext()->getUnoptimizedCFG();
Tom Care7bce3a12010-07-27 23:30:21 +000077 if (!PM)
78 PM = &LC->getParentMap();
Tom Carec4b5bd82010-07-23 23:04:53 +000079
80 if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
81 const CFGBlock *CB = BE->getBlock();
Tom Caref8906792010-08-03 21:24:13 +000082 reachable.insert(CB->getBlockID());
Tom Carec4b5bd82010-07-23 23:04:53 +000083 }
84 }
85
Tom Care7bce3a12010-07-27 23:30:21 +000086 // Bail out if we didn't get the CFG or the ParentMap.
87 if (!C || !PM)
Tom Carec4b5bd82010-07-23 23:04:53 +000088 return;
89
Jordy Rose5e04bdd2010-07-27 03:39:53 +000090 ASTContext &Ctx = B.getContext();
91
Tom Carec4b5bd82010-07-23 23:04:53 +000092 // Find CFGBlocks that were not covered by any node
93 for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
94 const CFGBlock *CB = *I;
95 // Check if the block is unreachable
Tom Caref8906792010-08-03 21:24:13 +000096 if (reachable.count(CB->getBlockID()))
Tom Care7bce3a12010-07-27 23:30:21 +000097 continue;
Tom Carec4b5bd82010-07-23 23:04:53 +000098
Tom Care7bce3a12010-07-27 23:30:21 +000099 // Find the entry points for this block
100 FindUnreachableEntryPoints(CB);
Jordy Rose5e04bdd2010-07-27 03:39:53 +0000101
Tom Care7bce3a12010-07-27 23:30:21 +0000102 // This block may have been pruned; check if we still want to report it
Tom Caref8906792010-08-03 21:24:13 +0000103 if (reachable.count(CB->getBlockID()))
Tom Care7bce3a12010-07-27 23:30:21 +0000104 continue;
105
106 // Check for false positives
107 if (CB->size() > 0 && isInvalidPath(CB, *PM))
108 continue;
109
Tom Care7bce3a12010-07-27 23:30:21 +0000110 // Special case for __builtin_unreachable.
111 // FIXME: This should be extended to include other unreachable markers,
112 // such as llvm_unreachable.
113 if (!CB->empty()) {
114 const Stmt *First = CB->front();
115 if (const CallExpr *CE = dyn_cast<CallExpr>(First)) {
116 if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable)
117 continue;
Jordy Rose5e04bdd2010-07-27 03:39:53 +0000118 }
Tom Carec4b5bd82010-07-23 23:04:53 +0000119 }
Tom Care7bce3a12010-07-27 23:30:21 +0000120
Tom Caref8906792010-08-03 21:24:13 +0000121 // We found a block that wasn't covered - find the statement to report
122 SourceRange SR;
123 SourceLocation SL;
124 if (const Stmt *S = getUnreachableStmt(CB)) {
125 SR = S->getSourceRange();
126 SL = S->getLocStart();
127 if (SR.isInvalid() || SL.isInvalid())
128 continue;
129 }
130 else
131 continue;
132
133 // Check if the SourceLocation is in a system header
134 const SourceManager &SM = B.getSourceManager();
135 if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL))
136 continue;
137
138 B.EmitBasicReport("Unreachable code", "Dead code", "This statement is never"
139 " executed", SL, SR);
Tom Carec4b5bd82010-07-23 23:04:53 +0000140 }
141}
142
143// Recursively finds the entry point(s) for this dead CFGBlock.
144void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB) {
145 bool allPredecessorsReachable = true;
146
Tom Caref8906792010-08-03 21:24:13 +0000147 visited.insert(CB->getBlockID());
Tom Carec4b5bd82010-07-23 23:04:53 +0000148
149 for (CFGBlock::const_pred_iterator I = CB->pred_begin(); I != CB->pred_end();
150 ++I) {
151 // Recurse over all unreachable blocks
Tom Caref8906792010-08-03 21:24:13 +0000152 if (!reachable.count((*I)->getBlockID())
153 && !visited.count((*I)->getBlockID())) {
Tom Carec4b5bd82010-07-23 23:04:53 +0000154 FindUnreachableEntryPoints(*I);
155 allPredecessorsReachable = false;
156 }
157 }
158
159 // If at least one predecessor is unreachable, mark this block as reachable
160 // so we don't report this block.
161 if (!allPredecessorsReachable) {
Tom Caref8906792010-08-03 21:24:13 +0000162 reachable.insert(CB->getBlockID());
Tom Carec4b5bd82010-07-23 23:04:53 +0000163 }
164}
165
Tom Caref8906792010-08-03 21:24:13 +0000166// Find the Stmt* in a CFGBlock for reporting a warning
167const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) {
168 if (CB->size() > 0)
169 return CB->front().getStmt();
170 else if (const Stmt *S = CB->getTerminator())
171 return S;
Tom Carec4b5bd82010-07-23 23:04:53 +0000172 else
Tom Caref8906792010-08-03 21:24:13 +0000173 return 0;
Tom Carec4b5bd82010-07-23 23:04:53 +0000174}
Tom Care7bce3a12010-07-27 23:30:21 +0000175
Tom Caref8906792010-08-03 21:24:13 +0000176// Determines if the path to this CFGBlock contained an element that infers this
177// block is a false positive. We assume that FindUnreachableEntryPoints has
178// already marked only the entry points to any dead code, so we need only to
179// find the condition that led to this block (the predecessor of this block.)
180// There will never be more than one predecessor.
Tom Care7bce3a12010-07-27 23:30:21 +0000181bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB,
182 const ParentMap &PM) {
Tom Caref8906792010-08-03 21:24:13 +0000183 // Assert this CFGBlock only has one or zero predecessors
184 assert(CB->pred_size() == 0 || CB->pred_size() == 1);
Tom Care7bce3a12010-07-27 23:30:21 +0000185
Tom Caref8906792010-08-03 21:24:13 +0000186 // If there are no predecessors, then this block is trivially unreachable
187 if (CB->pred_size() == 0)
188 return false;
189
190 const CFGBlock *pred = *CB->pred_begin();
191
192 // Get the predecessor block's terminator conditon
193 const Stmt *cond = pred->getTerminatorCondition();
194 assert(cond && "CFGBlock's predecessor has a terminator condition");
195
196 // Run each of the checks on the conditions
197 if (containsMacro(cond) || containsEnum(cond)
198 || containsStaticLocal(cond) || containsBuiltinOffsetOf(cond)
199 || containsStmt<SizeOfAlignOfExpr>(cond))
200 return true;
Tom Care7bce3a12010-07-27 23:30:21 +0000201
202 return false;
203}