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