clang  7.0.0svn
TestAfterDivZeroChecker.cpp
Go to the documentation of this file.
1 //== TestAfterDivZeroChecker.cpp - Test after division by zero checker --*--==//
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 defines TestAfterDivZeroChecker, a builtin check that performs checks
11 // for division by zero where the division occurs before comparison with zero.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "ClangSACheckers.h"
20 #include "llvm/ADT/FoldingSet.h"
21 
22 using namespace clang;
23 using namespace ento;
24 
25 namespace {
26 
27 class ZeroState {
28 private:
29  SymbolRef ZeroSymbol;
30  unsigned BlockID;
31  const StackFrameContext *SFC;
32 
33 public:
34  ZeroState(SymbolRef S, unsigned B, const StackFrameContext *SFC)
35  : ZeroSymbol(S), BlockID(B), SFC(SFC) {}
36 
37  const StackFrameContext *getStackFrameContext() const { return SFC; }
38 
39  bool operator==(const ZeroState &X) const {
40  return BlockID == X.BlockID && SFC == X.SFC && ZeroSymbol == X.ZeroSymbol;
41  }
42 
43  bool operator<(const ZeroState &X) const {
44  if (BlockID != X.BlockID)
45  return BlockID < X.BlockID;
46  if (SFC != X.SFC)
47  return SFC < X.SFC;
48  return ZeroSymbol < X.ZeroSymbol;
49  }
50 
51  void Profile(llvm::FoldingSetNodeID &ID) const {
52  ID.AddInteger(BlockID);
53  ID.AddPointer(SFC);
54  ID.AddPointer(ZeroSymbol);
55  }
56 };
57 
58 class DivisionBRVisitor : public BugReporterVisitorImpl<DivisionBRVisitor> {
59 private:
60  SymbolRef ZeroSymbol;
61  const StackFrameContext *SFC;
62  bool Satisfied;
63 
64 public:
65  DivisionBRVisitor(SymbolRef ZeroSymbol, const StackFrameContext *SFC)
66  : ZeroSymbol(ZeroSymbol), SFC(SFC), Satisfied(false) {}
67 
68  void Profile(llvm::FoldingSetNodeID &ID) const override {
69  ID.Add(ZeroSymbol);
70  ID.Add(SFC);
71  }
72 
73  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ,
74  const ExplodedNode *Pred,
75  BugReporterContext &BRC,
76  BugReport &BR) override;
77 };
78 
79 class TestAfterDivZeroChecker
80  : public Checker<check::PreStmt<BinaryOperator>, check::BranchCondition,
81  check::EndFunction> {
82  mutable std::unique_ptr<BuiltinBug> DivZeroBug;
83  void reportBug(SVal Val, CheckerContext &C) const;
84 
85 public:
86  void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
87  void checkBranchCondition(const Stmt *Condition, CheckerContext &C) const;
88  void checkEndFunction(CheckerContext &C) const;
89  void setDivZeroMap(SVal Var, CheckerContext &C) const;
90  bool hasDivZeroMap(SVal Var, const CheckerContext &C) const;
91  bool isZero(SVal S, CheckerContext &C) const;
92 };
93 } // end anonymous namespace
94 
95 REGISTER_SET_WITH_PROGRAMSTATE(DivZeroMap, ZeroState)
96 
97 std::shared_ptr<PathDiagnosticPiece>
98 DivisionBRVisitor::VisitNode(const ExplodedNode *Succ, const ExplodedNode *Pred,
99  BugReporterContext &BRC, BugReport &BR) {
100  if (Satisfied)
101  return nullptr;
102 
103  const Expr *E = nullptr;
104 
106  if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
107  BinaryOperator::Opcode Op = BO->getOpcode();
108  if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign ||
109  Op == BO_RemAssign) {
110  E = BO->getRHS();
111  }
112  }
113 
114  if (!E)
115  return nullptr;
116 
117  SVal S = Succ->getSVal(E);
118  if (ZeroSymbol == S.getAsSymbol() && SFC == Succ->getStackFrame()) {
119  Satisfied = true;
120 
121  // Construct a new PathDiagnosticPiece.
122  ProgramPoint P = Succ->getLocation();
125 
126  if (!L.isValid() || !L.asLocation().isValid())
127  return nullptr;
128 
129  return std::make_shared<PathDiagnosticEventPiece>(
130  L, "Division with compared value made here");
131  }
132 
133  return nullptr;
134 }
135 
136 bool TestAfterDivZeroChecker::isZero(SVal S, CheckerContext &C) const {
138 
139  if (!DSV)
140  return false;
141 
143  return !CM.assume(C.getState(), *DSV, true);
144 }
145 
146 void TestAfterDivZeroChecker::setDivZeroMap(SVal Var, CheckerContext &C) const {
147  SymbolRef SR = Var.getAsSymbol();
148  if (!SR)
149  return;
150 
152  State =
153  State->add<DivZeroMap>(ZeroState(SR, C.getBlockID(), C.getStackFrame()));
154  C.addTransition(State);
155 }
156 
157 bool TestAfterDivZeroChecker::hasDivZeroMap(SVal Var,
158  const CheckerContext &C) const {
159  SymbolRef SR = Var.getAsSymbol();
160  if (!SR)
161  return false;
162 
163  ZeroState ZS(SR, C.getBlockID(), C.getStackFrame());
164  return C.getState()->contains<DivZeroMap>(ZS);
165 }
166 
167 void TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const {
168  if (ExplodedNode *N = C.generateErrorNode(C.getState())) {
169  if (!DivZeroBug)
170  DivZeroBug.reset(new BuiltinBug(this, "Division by zero"));
171 
172  auto R = llvm::make_unique<BugReport>(
173  *DivZeroBug, "Value being compared against zero has already been used "
174  "for division",
175  N);
176 
177  R->addVisitor(llvm::make_unique<DivisionBRVisitor>(Val.getAsSymbol(),
178  C.getStackFrame()));
179  C.emitReport(std::move(R));
180  }
181 }
182 
183 void TestAfterDivZeroChecker::checkEndFunction(CheckerContext &C) const {
184  ProgramStateRef State = C.getState();
185 
186  DivZeroMapTy DivZeroes = State->get<DivZeroMap>();
187  if (DivZeroes.isEmpty())
188  return;
189 
190  DivZeroMapTy::Factory &F = State->get_context<DivZeroMap>();
191  for (llvm::ImmutableSet<ZeroState>::iterator I = DivZeroes.begin(),
192  E = DivZeroes.end();
193  I != E; ++I) {
194  ZeroState ZS = *I;
195  if (ZS.getStackFrameContext() == C.getStackFrame())
196  DivZeroes = F.remove(DivZeroes, ZS);
197  }
198  C.addTransition(State->set<DivZeroMap>(DivZeroes));
199 }
200 
201 void TestAfterDivZeroChecker::checkPreStmt(const BinaryOperator *B,
202  CheckerContext &C) const {
204  if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign ||
205  Op == BO_RemAssign) {
206  SVal S = C.getSVal(B->getRHS());
207 
208  if (!isZero(S, C))
209  setDivZeroMap(S, C);
210  }
211 }
212 
213 void TestAfterDivZeroChecker::checkBranchCondition(const Stmt *Condition,
214  CheckerContext &C) const {
215  if (const BinaryOperator *B = dyn_cast<BinaryOperator>(Condition)) {
216  if (B->isComparisonOp()) {
217  const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(B->getRHS());
218  bool LRHS = true;
219  if (!IntLiteral) {
220  IntLiteral = dyn_cast<IntegerLiteral>(B->getLHS());
221  LRHS = false;
222  }
223 
224  if (!IntLiteral || IntLiteral->getValue() != 0)
225  return;
226 
227  SVal Val = C.getSVal(LRHS ? B->getLHS() : B->getRHS());
228  if (hasDivZeroMap(Val, C))
229  reportBug(Val, C);
230  }
231  } else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(Condition)) {
232  if (U->getOpcode() == UO_LNot) {
233  SVal Val;
234  if (const ImplicitCastExpr *I =
235  dyn_cast<ImplicitCastExpr>(U->getSubExpr()))
236  Val = C.getSVal(I->getSubExpr());
237 
238  if (hasDivZeroMap(Val, C))
239  reportBug(Val, C);
240  else {
241  Val = C.getSVal(U->getSubExpr());
242  if (hasDivZeroMap(Val, C))
243  reportBug(Val, C);
244  }
245  }
246  } else if (const ImplicitCastExpr *IE =
247  dyn_cast<ImplicitCastExpr>(Condition)) {
248  SVal Val = C.getSVal(IE->getSubExpr());
249 
250  if (hasDivZeroMap(Val, C))
251  reportBug(Val, C);
252  else {
253  SVal Val = C.getSVal(Condition);
254 
255  if (hasDivZeroMap(Val, C))
256  reportBug(Val, C);
257  }
258  }
259 }
260 
261 void ento::registerTestAfterDivZeroChecker(CheckerManager &mgr) {
262  mgr.registerChecker<TestAfterDivZeroChecker>();
263 }
virtual ProgramStateRef assume(ProgramStateRef state, DefinedSVal Cond, bool Assumption)=0
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
bool operator==(CanQual< T > x, CanQual< U > y)
Stmt - This represents one statement.
Definition: Stmt.h:66
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
Opcode getOpcode() const
Definition: Expr.h:3106
StringRef P
SVal getSVal(const Stmt *S) const
Get the value of arbitrary expressions at this point in the path.
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
Symbolic value.
Definition: SymExpr.h:30
LineState State
This class provides a convenience implementation for clone() using the Curiously-Recurring Template P...
Optional< T > getLocationAs() const LLVM_LVALUE_FUNCTION
BinaryOperatorKind
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3065
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
Definition: SVals.cpp:127
Expr - This represents one expression.
Definition: Expr.h:106
UnaryOperator - This represents the unary-expression&#39;s (except sizeof and alignof), the postinc/postdec operators from postfix-expression, and various extensions.
Definition: Expr.h:1782
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
Definition: SVals.h:112
ConstraintManager & getConstraintManager()
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
#define false
Definition: stdbool.h:33
CHECKER * registerChecker()
Used to register checkers.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:76
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Definition: Expr.h:2902
SVal getSVal(const Stmt *S) const
Get the value of an arbitrary expression at this node.
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.
Expr * getLHS() const
Definition: Expr.h:3109
unsigned getBlockID() const
Get the blockID.
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
llvm::APInt getValue() const
Definition: Expr.h:1295
const StackFrameContext * getStackFrame() const
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:13462
Expr * getRHS() const
Definition: Expr.h:3111
const StackFrameContext * getStackFrame() const
This class provides an interface through which checkers can create individual bug reports...
Definition: BugReporter.h:70
static bool isComparisonOp(Opcode Opc)
Definition: Expr.h:3155
SourceManager & getSourceManager()
Definition: BugReporter.h:574