clang  6.0.0svn
UndefBranchChecker.cpp
Go to the documentation of this file.
1 //=== UndefBranchChecker.cpp -----------------------------------*- 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 //
10 // This file defines UndefBranchChecker, which checks for undefined branch
11 // condition.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "ClangSACheckers.h"
20 #include <utility>
21 
22 using namespace clang;
23 using namespace ento;
24 
25 namespace {
26 
27 class UndefBranchChecker : public Checker<check::BranchCondition> {
28  mutable std::unique_ptr<BuiltinBug> BT;
29 
30  struct FindUndefExpr {
31  ProgramStateRef St;
32  const LocationContext *LCtx;
33 
34  FindUndefExpr(ProgramStateRef S, const LocationContext *L)
35  : St(std::move(S)), LCtx(L) {}
36 
37  const Expr *FindExpr(const Expr *Ex) {
38  if (!MatchesCriteria(Ex))
39  return nullptr;
40 
41  for (const Stmt *SubStmt : Ex->children())
42  if (const Expr *ExI = dyn_cast_or_null<Expr>(SubStmt))
43  if (const Expr *E2 = FindExpr(ExI))
44  return E2;
45 
46  return Ex;
47  }
48 
49  bool MatchesCriteria(const Expr *Ex) {
50  return St->getSVal(Ex, LCtx).isUndef();
51  }
52  };
53 
54 public:
55  void checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const;
56 };
57 
58 }
59 
60 void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
61  CheckerContext &Ctx) const {
62  SVal X = Ctx.getState()->getSVal(Condition, Ctx.getLocationContext());
63  if (X.isUndef()) {
64  // Generate a sink node, which implicitly marks both outgoing branches as
65  // infeasible.
67  if (N) {
68  if (!BT)
69  BT.reset(new BuiltinBug(
70  this, "Branch condition evaluates to a garbage value"));
71 
72  // What's going on here: we want to highlight the subexpression of the
73  // condition that is the most likely source of the "uninitialized
74  // branch condition." We do a recursive walk of the condition's
75  // subexpressions and roughly look for the most nested subexpression
76  // that binds to Undefined. We then highlight that expression's range.
77 
78  // Get the predecessor node and check if is a PostStmt with the Stmt
79  // being the terminator condition. We want to inspect the state
80  // of that node instead because it will contain main information about
81  // the subexpressions.
82 
83  // Note: any predecessor will do. They should have identical state,
84  // since all the BlockEdge did was act as an error sink since the value
85  // had to already be undefined.
86  assert (!N->pred_empty());
87  const Expr *Ex = cast<Expr>(Condition);
88  ExplodedNode *PrevN = *N->pred_begin();
89  ProgramPoint P = PrevN->getLocation();
90  ProgramStateRef St = N->getState();
91 
92  if (Optional<PostStmt> PS = P.getAs<PostStmt>())
93  if (PS->getStmt() == Ex)
94  St = PrevN->getState();
95 
96  FindUndefExpr FindIt(St, Ctx.getLocationContext());
97  Ex = FindIt.FindExpr(Ex);
98 
99  // Emit the bug report.
100  auto R = llvm::make_unique<BugReport>(*BT, BT->getDescription(), N);
102  R->addRange(Ex->getSourceRange());
103 
104  Ctx.emitReport(std::move(R));
105  }
106  }
107 }
108 
109 void ento::registerUndefBranchChecker(CheckerManager &mgr) {
110  mgr.registerChecker<UndefBranchChecker>();
111 }
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
Stmt - This represents one statement.
Definition: Stmt.h:66
StringRef P
const ProgramStateRef & getState() const
Definition: Format.h:1900
child_range children()
Definition: Stmt.cpp:226
Expr - This represents one expression.
Definition: Expr.h:106
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
CHECKER * registerChecker()
Used to register checkers.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:63
Dataflow Directional Tag Classes.
const ProgramStateRef & getState() const
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
Definition: SemaDecl.cpp:13010
bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, bool IsArg=false, bool EnableNullFPSuppression=true)
Attempts to add visitors to trace a null or undefined value back to its point of origin, whether it is a symbol constrained to null or an explicit assignment.
pred_iterator pred_begin()
bool isUndef() const
Definition: SVals.h:129
Optional< T > getAs() const
Convert to the specified ProgramPoint type, returning None if this ProgramPoint is not of the desired...
Definition: ProgramPoint.h:151
const LocationContext * getLocationContext() const