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