xref: /aosp_15_r20/external/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
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