blob: 432967e00c2b9bf0a48ebf07e7a45ec9dca0e324 [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 Care06009182010-08-05 17:53:44 +0000152 if (!reachable.count((*I)->getBlockID())) {
153 // At least one predeccessor was unreachable
Tom Carec4b5bd82010-07-23 23:04:53 +0000154 allPredecessorsReachable = false;
Tom Care06009182010-08-05 17:53:44 +0000155
156 // Only visit the block once
157 if (!visited.count((*I)->getBlockID()))
158 FindUnreachableEntryPoints(*I);
Tom Carec4b5bd82010-07-23 23:04:53 +0000159 }
160 }
161
162 // If at least one predecessor is unreachable, mark this block as reachable
163 // so we don't report this block.
164 if (!allPredecessorsReachable) {
Tom Caref8906792010-08-03 21:24:13 +0000165 reachable.insert(CB->getBlockID());
Tom Carec4b5bd82010-07-23 23:04:53 +0000166 }
167}
168
Tom Caref8906792010-08-03 21:24:13 +0000169// Find the Stmt* in a CFGBlock for reporting a warning
170const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) {
171 if (CB->size() > 0)
172 return CB->front().getStmt();
173 else if (const Stmt *S = CB->getTerminator())
174 return S;
Tom Carec4b5bd82010-07-23 23:04:53 +0000175 else
Tom Caref8906792010-08-03 21:24:13 +0000176 return 0;
Tom Carec4b5bd82010-07-23 23:04:53 +0000177}
Tom Care7bce3a12010-07-27 23:30:21 +0000178
Tom Caref8906792010-08-03 21:24:13 +0000179// Determines if the path to this CFGBlock contained an element that infers this
180// block is a false positive. We assume that FindUnreachableEntryPoints has
181// already marked only the entry points to any dead code, so we need only to
182// find the condition that led to this block (the predecessor of this block.)
183// There will never be more than one predecessor.
Tom Care7bce3a12010-07-27 23:30:21 +0000184bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB,
185 const ParentMap &PM) {
Tom Caref8906792010-08-03 21:24:13 +0000186 // Assert this CFGBlock only has one or zero predecessors
187 assert(CB->pred_size() == 0 || CB->pred_size() == 1);
Tom Care7bce3a12010-07-27 23:30:21 +0000188
Tom Caref8906792010-08-03 21:24:13 +0000189 // If there are no predecessors, then this block is trivially unreachable
190 if (CB->pred_size() == 0)
191 return false;
192
193 const CFGBlock *pred = *CB->pred_begin();
194
195 // Get the predecessor block's terminator conditon
196 const Stmt *cond = pred->getTerminatorCondition();
197 assert(cond && "CFGBlock's predecessor has a terminator condition");
198
199 // Run each of the checks on the conditions
200 if (containsMacro(cond) || containsEnum(cond)
201 || containsStaticLocal(cond) || containsBuiltinOffsetOf(cond)
202 || containsStmt<SizeOfAlignOfExpr>(cond))
203 return true;
Tom Care7bce3a12010-07-27 23:30:21 +0000204
205 return false;
206}