xref: /minix3/external/bsd/llvm/dist/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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