1c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines//== TestAfterDivZeroChecker.cpp - Test after division by zero checker --*--==//
2c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines//
3c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines//                     The LLVM Compiler Infrastructure
4c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines//
5c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines// This file is distributed under the University of Illinois Open Source
6c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines// License. See LICENSE.TXT for details.
7c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines//
8c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines//===----------------------------------------------------------------------===//
9c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines//
10c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines// This defines TestAfterDivZeroChecker, a builtin check that performs checks
11c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines//  for division by zero where the division occurs before comparison with zero.
12c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines//
13c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines//===----------------------------------------------------------------------===//
14c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
15c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines#include "ClangSACheckers.h"
16c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines#include "clang/StaticAnalyzer/Core/Checker.h"
18c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
19c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines#include "llvm/ADT/FoldingSet.h"
21c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
22c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesusing namespace clang;
23c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesusing namespace ento;
24c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
25c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesnamespace {
26c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
27c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesclass ZeroState {
28c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesprivate:
29c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  SymbolRef ZeroSymbol;
30c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  unsigned BlockID;
31c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  const StackFrameContext *SFC;
32c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
33c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinespublic:
34c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  ZeroState(SymbolRef S, unsigned B, const StackFrameContext *SFC)
35c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      : ZeroSymbol(S), BlockID(B), SFC(SFC) {}
36c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
37c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  const StackFrameContext *getStackFrameContext() const { return SFC; }
38c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
39c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  bool operator==(const ZeroState &X) const {
40c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return BlockID == X.BlockID && SFC == X.SFC && ZeroSymbol == X.ZeroSymbol;
41c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
42c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
43c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  bool operator<(const ZeroState &X) const {
44c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (BlockID != X.BlockID)
45c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      return BlockID < X.BlockID;
46c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (SFC != X.SFC)
47c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      return SFC < X.SFC;
48c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return ZeroSymbol < X.ZeroSymbol;
49c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
50c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
51c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  void Profile(llvm::FoldingSetNodeID &ID) const {
52c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    ID.AddInteger(BlockID);
53c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    ID.AddPointer(SFC);
54c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    ID.AddPointer(ZeroSymbol);
55c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
56c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines};
57c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
58c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesclass DivisionBRVisitor : public BugReporterVisitorImpl<DivisionBRVisitor> {
59c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesprivate:
60c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  SymbolRef ZeroSymbol;
61c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  const StackFrameContext *SFC;
62176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  bool Satisfied;
63c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
64c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinespublic:
65c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  DivisionBRVisitor(SymbolRef ZeroSymbol, const StackFrameContext *SFC)
66176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines      : ZeroSymbol(ZeroSymbol), SFC(SFC), Satisfied(false) {}
67c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
68c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  void Profile(llvm::FoldingSetNodeID &ID) const override {
69c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    ID.Add(ZeroSymbol);
70c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    ID.Add(SFC);
71c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
72c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
73c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
74c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                                 const ExplodedNode *Pred,
75c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                                 BugReporterContext &BRC,
76c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                                 BugReport &BR) override;
77c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines};
78c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
79c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesclass TestAfterDivZeroChecker
80c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    : public Checker<check::PreStmt<BinaryOperator>, check::BranchCondition,
81c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                     check::EndFunction> {
82c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  mutable std::unique_ptr<BuiltinBug> DivZeroBug;
83c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  void reportBug(SVal Val, CheckerContext &C) const;
84c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
85c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinespublic:
86c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
87c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  void checkBranchCondition(const Stmt *Condition, CheckerContext &C) const;
88c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  void checkEndFunction(CheckerContext &C) const;
89c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  void setDivZeroMap(SVal Var, CheckerContext &C) const;
90c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  bool hasDivZeroMap(SVal Var, const CheckerContext &C) const;
91c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  bool isZero(SVal S, CheckerContext &C) const;
92c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines};
93c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines} // end anonymous namespace
94c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
95c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen HinesREGISTER_SET_WITH_PROGRAMSTATE(DivZeroMap, ZeroState)
96c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
97c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen HinesPathDiagnosticPiece *DivisionBRVisitor::VisitNode(const ExplodedNode *Succ,
98c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                                                  const ExplodedNode *Pred,
99c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                                                  BugReporterContext &BRC,
100c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                                                  BugReport &BR) {
101c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (Satisfied)
102c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return nullptr;
103c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
104c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  const Expr *E = nullptr;
105c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
106c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>())
107c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
108c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      BinaryOperator::Opcode Op = BO->getOpcode();
109c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign ||
110c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines          Op == BO_RemAssign) {
111c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        E = BO->getRHS();
112c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      }
113c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
114c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
115c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (!E)
116c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return nullptr;
117c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
118c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  ProgramStateRef State = Succ->getState();
119c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  SVal S = State->getSVal(E, Succ->getLocationContext());
120c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (ZeroSymbol == S.getAsSymbol() && SFC == Succ->getStackFrame()) {
121c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    Satisfied = true;
122c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
123c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    // Construct a new PathDiagnosticPiece.
124c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    ProgramPoint P = Succ->getLocation();
125c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    PathDiagnosticLocation L =
126c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        PathDiagnosticLocation::create(P, BRC.getSourceManager());
127c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
128c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (!L.isValid() || !L.asLocation().isValid())
129c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      return nullptr;
130c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
131c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return new PathDiagnosticEventPiece(
132c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        L, "Division with compared value made here");
133c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
134c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
135c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  return nullptr;
136c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
137c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
138c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesbool TestAfterDivZeroChecker::isZero(SVal S, CheckerContext &C) const {
139c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  Optional<DefinedSVal> DSV = S.getAs<DefinedSVal>();
140c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
141c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (!DSV)
142c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return false;
143c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
144c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  ConstraintManager &CM = C.getConstraintManager();
145c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  return !CM.assume(C.getState(), *DSV, true);
146c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
147c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
148c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesvoid TestAfterDivZeroChecker::setDivZeroMap(SVal Var, CheckerContext &C) const {
149c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  SymbolRef SR = Var.getAsSymbol();
150c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (!SR)
151c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return;
152c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
153c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  ProgramStateRef State = C.getState();
154c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  State =
155c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      State->add<DivZeroMap>(ZeroState(SR, C.getBlockID(), C.getStackFrame()));
156c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  C.addTransition(State);
157c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
158c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
159c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesbool TestAfterDivZeroChecker::hasDivZeroMap(SVal Var,
160c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                                            const CheckerContext &C) const {
161c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  SymbolRef SR = Var.getAsSymbol();
162c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (!SR)
163c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return false;
164c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
165c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  ZeroState ZS(SR, C.getBlockID(), C.getStackFrame());
166c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  return C.getState()->contains<DivZeroMap>(ZS);
167c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
168c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
169c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesvoid TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const {
17087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  if (ExplodedNode *N = C.generateErrorNode(C.getState())) {
171c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (!DivZeroBug)
172c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      DivZeroBug.reset(new BuiltinBug(this, "Division by zero"));
173c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
17487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    auto R = llvm::make_unique<BugReport>(
17587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        *DivZeroBug, "Value being compared against zero has already been used "
17687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                     "for division",
17787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        N);
178c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
179176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    R->addVisitor(llvm::make_unique<DivisionBRVisitor>(Val.getAsSymbol(),
180176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                                                       C.getStackFrame()));
18187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    C.emitReport(std::move(R));
182c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
183c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
184c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
185c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesvoid TestAfterDivZeroChecker::checkEndFunction(CheckerContext &C) const {
186c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  ProgramStateRef State = C.getState();
187c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
188c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  DivZeroMapTy DivZeroes = State->get<DivZeroMap>();
189c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (DivZeroes.isEmpty())
190c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return;
191c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
192c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  DivZeroMapTy::Factory &F = State->get_context<DivZeroMap>();
193c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  for (llvm::ImmutableSet<ZeroState>::iterator I = DivZeroes.begin(),
194c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                                               E = DivZeroes.end();
195c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines       I != E; ++I) {
196c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    ZeroState ZS = *I;
197c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (ZS.getStackFrameContext() == C.getStackFrame())
198c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      DivZeroes = F.remove(DivZeroes, ZS);
199c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
200c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  C.addTransition(State->set<DivZeroMap>(DivZeroes));
201c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
202c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
203c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesvoid TestAfterDivZeroChecker::checkPreStmt(const BinaryOperator *B,
204c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                                           CheckerContext &C) const {
205c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  BinaryOperator::Opcode Op = B->getOpcode();
206c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign ||
207c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      Op == BO_RemAssign) {
208c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    SVal S = C.getSVal(B->getRHS());
209c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
210c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (!isZero(S, C))
211c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      setDivZeroMap(S, C);
212c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
213c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
214c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
215c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesvoid TestAfterDivZeroChecker::checkBranchCondition(const Stmt *Condition,
216c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                                                   CheckerContext &C) const {
217c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (const BinaryOperator *B = dyn_cast<BinaryOperator>(Condition)) {
218c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (B->isComparisonOp()) {
219c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(B->getRHS());
220c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      bool LRHS = true;
221c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      if (!IntLiteral) {
222c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        IntLiteral = dyn_cast<IntegerLiteral>(B->getLHS());
223c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        LRHS = false;
224c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      }
225c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
226c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      if (!IntLiteral || IntLiteral->getValue() != 0)
227c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        return;
228c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
229c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      SVal Val = C.getSVal(LRHS ? B->getLHS() : B->getRHS());
230c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      if (hasDivZeroMap(Val, C))
231c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        reportBug(Val, C);
232c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
233c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  } else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(Condition)) {
234c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (U->getOpcode() == UO_LNot) {
235c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      SVal Val;
236c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      if (const ImplicitCastExpr *I =
237c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines              dyn_cast<ImplicitCastExpr>(U->getSubExpr()))
238c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        Val = C.getSVal(I->getSubExpr());
239c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
240c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      if (hasDivZeroMap(Val, C))
241c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        reportBug(Val, C);
242c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      else {
243c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        Val = C.getSVal(U->getSubExpr());
244c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        if (hasDivZeroMap(Val, C))
245c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines          reportBug(Val, C);
246c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      }
247c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
248c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  } else if (const ImplicitCastExpr *IE =
249c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                 dyn_cast<ImplicitCastExpr>(Condition)) {
250c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    SVal Val = C.getSVal(IE->getSubExpr());
251c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
252c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (hasDivZeroMap(Val, C))
253c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      reportBug(Val, C);
254c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    else {
255c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      SVal Val = C.getSVal(Condition);
256c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
257c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      if (hasDivZeroMap(Val, C))
258c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        reportBug(Val, C);
259c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
260c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
261c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
262c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
263c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesvoid ento::registerTestAfterDivZeroChecker(CheckerManager &mgr) {
264c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  mgr.registerChecker<TestAfterDivZeroChecker>();
265c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
266