UnreachableCodeChecker.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. //==- UnreachableCodeChecker.cpp - Generalized dead code checker -*- C++ -*-==//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. // This file implements a generalized unreachable code checker using a
  9. // path-sensitive analysis. We mark any path visited, and then walk the CFG as a
  10. // post-analysis to determine what was never visited.
  11. //
  12. // A similar flow-sensitive only check exists in Analysis/ReachableCode.cpp
  13. //===----------------------------------------------------------------------===//
  14. #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
  15. #include "clang/AST/ParentMap.h"
  16. #include "clang/Basic/Builtins.h"
  17. #include "clang/Basic/SourceManager.h"
  18. #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
  19. #include "clang/StaticAnalyzer/Core/Checker.h"
  20. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  21. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  22. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
  23. #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
  24. #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
  25. #include "llvm/ADT/SmallSet.h"
  26. using namespace clang;
  27. using namespace ento;
  28. namespace {
  29. class UnreachableCodeChecker : public Checker<check::EndAnalysis> {
  30. public:
  31. void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,
  32. ExprEngine &Eng) const;
  33. private:
  34. typedef llvm::SmallSet<unsigned, 32> CFGBlocksSet;
  35. static inline const Stmt *getUnreachableStmt(const CFGBlock *CB);
  36. static void FindUnreachableEntryPoints(const CFGBlock *CB,
  37. CFGBlocksSet &reachable,
  38. CFGBlocksSet &visited);
  39. static bool isInvalidPath(const CFGBlock *CB, const ParentMap &PM);
  40. static inline bool isEmptyCFGBlock(const CFGBlock *CB);
  41. };
  42. }
  43. void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
  44. BugReporter &B,
  45. ExprEngine &Eng) const {
  46. CFGBlocksSet reachable, visited;
  47. if (Eng.hasWorkRemaining())
  48. return;
  49. const Decl *D = nullptr;
  50. CFG *C = nullptr;
  51. const ParentMap *PM = nullptr;
  52. const LocationContext *LC = nullptr;
  53. // Iterate over ExplodedGraph
  54. for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end();
  55. I != E; ++I) {
  56. const ProgramPoint &P = I->getLocation();
  57. LC = P.getLocationContext();
  58. if (!LC->inTopFrame())
  59. continue;
  60. if (!D)
  61. D = LC->getAnalysisDeclContext()->getDecl();
  62. // Save the CFG if we don't have it already
  63. if (!C)
  64. C = LC->getAnalysisDeclContext()->getUnoptimizedCFG();
  65. if (!PM)
  66. PM = &LC->getParentMap();
  67. if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
  68. const CFGBlock *CB = BE->getBlock();
  69. reachable.insert(CB->getBlockID());
  70. }
  71. }
  72. // Bail out if we didn't get the CFG or the ParentMap.
  73. if (!D || !C || !PM)
  74. return;
  75. // Don't do anything for template instantiations. Proving that code
  76. // in a template instantiation is unreachable means proving that it is
  77. // unreachable in all instantiations.
  78. if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
  79. if (FD->isTemplateInstantiation())
  80. return;
  81. // Find CFGBlocks that were not covered by any node
  82. for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) {
  83. const CFGBlock *CB = *I;
  84. // Check if the block is unreachable
  85. if (reachable.count(CB->getBlockID()))
  86. continue;
  87. // Check if the block is empty (an artificial block)
  88. if (isEmptyCFGBlock(CB))
  89. continue;
  90. // Find the entry points for this block
  91. if (!visited.count(CB->getBlockID()))
  92. FindUnreachableEntryPoints(CB, reachable, visited);
  93. // This block may have been pruned; check if we still want to report it
  94. if (reachable.count(CB->getBlockID()))
  95. continue;
  96. // Check for false positives
  97. if (isInvalidPath(CB, *PM))
  98. continue;
  99. // It is good practice to always have a "default" label in a "switch", even
  100. // if we should never get there. It can be used to detect errors, for
  101. // instance. Unreachable code directly under a "default" label is therefore
  102. // likely to be a false positive.
  103. if (const Stmt *label = CB->getLabel())
  104. if (label->getStmtClass() == Stmt::DefaultStmtClass)
  105. continue;
  106. // Special case for __builtin_unreachable.
  107. // FIXME: This should be extended to include other unreachable markers,
  108. // such as llvm_unreachable.
  109. if (!CB->empty()) {
  110. bool foundUnreachable = false;
  111. for (CFGBlock::const_iterator ci = CB->begin(), ce = CB->end();
  112. ci != ce; ++ci) {
  113. if (Optional<CFGStmt> S = (*ci).getAs<CFGStmt>())
  114. if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
  115. if (CE->getBuiltinCallee() == Builtin::BI__builtin_unreachable ||
  116. CE->isBuiltinAssumeFalse(Eng.getContext())) {
  117. foundUnreachable = true;
  118. break;
  119. }
  120. }
  121. }
  122. if (foundUnreachable)
  123. continue;
  124. }
  125. // We found a block that wasn't covered - find the statement to report
  126. SourceRange SR;
  127. PathDiagnosticLocation DL;
  128. SourceLocation SL;
  129. if (const Stmt *S = getUnreachableStmt(CB)) {
  130. // In macros, 'do {...} while (0)' is often used. Don't warn about the
  131. // condition 0 when it is unreachable.
  132. if (S->getBeginLoc().isMacroID())
  133. if (const auto *I = dyn_cast<IntegerLiteral>(S))
  134. if (I->getValue() == 0ULL)
  135. if (const Stmt *Parent = PM->getParent(S))
  136. if (isa<DoStmt>(Parent))
  137. continue;
  138. SR = S->getSourceRange();
  139. DL = PathDiagnosticLocation::createBegin(S, B.getSourceManager(), LC);
  140. SL = DL.asLocation();
  141. if (SR.isInvalid() || !SL.isValid())
  142. continue;
  143. }
  144. else
  145. continue;
  146. // Check if the SourceLocation is in a system header
  147. const SourceManager &SM = B.getSourceManager();
  148. if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL))
  149. continue;
  150. B.EmitBasicReport(D, this, "Unreachable code", categories::UnusedCode,
  151. "This statement is never executed", DL, SR);
  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. for (CFGBlock::const_pred_iterator I = CB->pred_begin(), E = CB->pred_end();
  160. I != E; ++I) {
  161. if (!*I)
  162. continue;
  163. if (!reachable.count((*I)->getBlockID())) {
  164. // If we find an unreachable predecessor, mark this block as reachable so
  165. // we don't report this block
  166. reachable.insert(CB->getBlockID());
  167. if (!visited.count((*I)->getBlockID()))
  168. // If we haven't previously visited the unreachable predecessor, recurse
  169. FindUnreachableEntryPoints(*I, reachable, visited);
  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 (Optional<CFGStmt> S = I->getAs<CFGStmt>()) {
  177. if (!isa<DeclStmt>(S->getStmt()))
  178. return S->getStmt();
  179. }
  180. }
  181. if (const Stmt *S = CB->getTerminatorStmt())
  182. return S;
  183. else
  184. return nullptr;
  185. }
  186. // Determines if the path to this CFGBlock contained an element that infers this
  187. // block is a false positive. We assume that FindUnreachableEntryPoints has
  188. // already marked only the entry points to any dead code, so we need only to
  189. // find the condition that led to this block (the predecessor of this block.)
  190. // There will never be more than one predecessor.
  191. bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB,
  192. const ParentMap &PM) {
  193. // We only expect a predecessor size of 0 or 1. If it is >1, then an external
  194. // condition has broken our assumption (for example, a sink being placed by
  195. // another check). In these cases, we choose not to report.
  196. if (CB->pred_size() > 1)
  197. return true;
  198. // If there are no predecessors, then this block is trivially unreachable
  199. if (CB->pred_size() == 0)
  200. return false;
  201. const CFGBlock *pred = *CB->pred_begin();
  202. if (!pred)
  203. return false;
  204. // Get the predecessor block's terminator condition
  205. const Stmt *cond = pred->getTerminatorCondition();
  206. //assert(cond && "CFGBlock's predecessor has a terminator condition");
  207. // The previous assertion is invalid in some cases (eg do/while). Leaving
  208. // reporting of these situations on at the moment to help triage these cases.
  209. if (!cond)
  210. return false;
  211. // Run each of the checks on the conditions
  212. return containsMacro(cond) || containsEnum(cond) ||
  213. containsStaticLocal(cond) || containsBuiltinOffsetOf(cond) ||
  214. containsStmt<UnaryExprOrTypeTraitExpr>(cond);
  215. }
  216. // Returns true if the given CFGBlock is empty
  217. bool UnreachableCodeChecker::isEmptyCFGBlock(const CFGBlock *CB) {
  218. return CB->getLabel() == nullptr // No labels
  219. && CB->size() == 0 // No statements
  220. && !CB->getTerminatorStmt(); // No terminator
  221. }
  222. void ento::registerUnreachableCodeChecker(CheckerManager &mgr) {
  223. mgr.registerChecker<UnreachableCodeChecker>();
  224. }
  225. bool ento::shouldRegisterUnreachableCodeChecker(const CheckerManager &mgr) {
  226. return true;
  227. }