12754fe60SDimitry Andric //== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==//
22754fe60SDimitry Andric //
32754fe60SDimitry Andric // The LLVM Compiler Infrastructure
42754fe60SDimitry Andric //
52754fe60SDimitry Andric // This file is distributed under the University of Illinois Open Source
62754fe60SDimitry Andric // License. See LICENSE.TXT for details.
72754fe60SDimitry Andric //
82754fe60SDimitry Andric //===----------------------------------------------------------------------===//
92754fe60SDimitry Andric //
102754fe60SDimitry Andric // This defines DivZeroChecker, a builtin check in ExprEngine that performs
112754fe60SDimitry Andric // checks for division by zeros.
122754fe60SDimitry Andric //
132754fe60SDimitry Andric //===----------------------------------------------------------------------===//
142754fe60SDimitry Andric
15*b5893f02SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
16139f7f9bSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
173b0f4066SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
183b0f4066SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
193b0f4066SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
202754fe60SDimitry Andric
212754fe60SDimitry Andric using namespace clang;
222754fe60SDimitry Andric using namespace ento;
232754fe60SDimitry Andric
242754fe60SDimitry Andric namespace {
253b0f4066SDimitry Andric class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {
2659d1ed5bSDimitry Andric mutable std::unique_ptr<BuiltinBug> BT;
274ba319b5SDimitry Andric void reportBug(const char *Msg, ProgramStateRef StateZero, CheckerContext &C,
284ba319b5SDimitry Andric std::unique_ptr<BugReporterVisitor> Visitor = nullptr) const;
294ba319b5SDimitry Andric
302754fe60SDimitry Andric public:
313b0f4066SDimitry Andric void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
322754fe60SDimitry Andric };
332754fe60SDimitry Andric } // end anonymous namespace
342754fe60SDimitry Andric
getDenomExpr(const ExplodedNode * N)35*b5893f02SDimitry Andric static const Expr *getDenomExpr(const ExplodedNode *N) {
36*b5893f02SDimitry Andric const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
37*b5893f02SDimitry Andric if (const auto *BE = dyn_cast<BinaryOperator>(S))
38*b5893f02SDimitry Andric return BE->getRHS();
39*b5893f02SDimitry Andric return nullptr;
40*b5893f02SDimitry Andric }
41*b5893f02SDimitry Andric
reportBug(const char * Msg,ProgramStateRef StateZero,CheckerContext & C,std::unique_ptr<BugReporterVisitor> Visitor) const424ba319b5SDimitry Andric void DivZeroChecker::reportBug(
434ba319b5SDimitry Andric const char *Msg, ProgramStateRef StateZero, CheckerContext &C,
444ba319b5SDimitry Andric std::unique_ptr<BugReporterVisitor> Visitor) const {
450623d748SDimitry Andric if (ExplodedNode *N = C.generateErrorNode(StateZero)) {
46dff0c46cSDimitry Andric if (!BT)
4759d1ed5bSDimitry Andric BT.reset(new BuiltinBug(this, "Division by zero"));
48dff0c46cSDimitry Andric
493dac3a9bSDimitry Andric auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
504ba319b5SDimitry Andric R->addVisitor(std::move(Visitor));
51*b5893f02SDimitry Andric bugreporter::trackExpressionValue(N, getDenomExpr(N), *R);
523dac3a9bSDimitry Andric C.emitReport(std::move(R));
53dff0c46cSDimitry Andric }
54dff0c46cSDimitry Andric }
55dff0c46cSDimitry Andric
checkPreStmt(const BinaryOperator * B,CheckerContext & C) const563b0f4066SDimitry Andric void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
573b0f4066SDimitry Andric CheckerContext &C) const {
582754fe60SDimitry Andric BinaryOperator::Opcode Op = B->getOpcode();
592754fe60SDimitry Andric if (Op != BO_Div &&
602754fe60SDimitry Andric Op != BO_Rem &&
612754fe60SDimitry Andric Op != BO_DivAssign &&
622754fe60SDimitry Andric Op != BO_RemAssign)
632754fe60SDimitry Andric return;
642754fe60SDimitry Andric
657ae0e2c9SDimitry Andric if (!B->getRHS()->getType()->isScalarType())
662754fe60SDimitry Andric return;
672754fe60SDimitry Andric
684ba319b5SDimitry Andric SVal Denom = C.getSVal(B->getRHS());
69139f7f9bSDimitry Andric Optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
702754fe60SDimitry Andric
712754fe60SDimitry Andric // Divide-by-undefined handled in the generic checking for uses of
722754fe60SDimitry Andric // undefined values.
732754fe60SDimitry Andric if (!DV)
742754fe60SDimitry Andric return;
752754fe60SDimitry Andric
762754fe60SDimitry Andric // Check for divide by zero.
772754fe60SDimitry Andric ConstraintManager &CM = C.getConstraintManager();
78dff0c46cSDimitry Andric ProgramStateRef stateNotZero, stateZero;
7959d1ed5bSDimitry Andric std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
802754fe60SDimitry Andric
81dff0c46cSDimitry Andric if (!stateNotZero) {
82dff0c46cSDimitry Andric assert(stateZero);
83dff0c46cSDimitry Andric reportBug("Division by zero", stateZero, C);
84dff0c46cSDimitry Andric return;
852754fe60SDimitry Andric }
86dff0c46cSDimitry Andric
87dff0c46cSDimitry Andric bool TaintedD = C.getState()->isTainted(*DV);
88dff0c46cSDimitry Andric if ((stateNotZero && stateZero && TaintedD)) {
894ba319b5SDimitry Andric reportBug("Division by a tainted value, possibly zero", stateZero, C,
904ba319b5SDimitry Andric llvm::make_unique<TaintBugVisitor>(*DV));
912754fe60SDimitry Andric return;
922754fe60SDimitry Andric }
932754fe60SDimitry Andric
942754fe60SDimitry Andric // If we get here, then the denom should not be zero. We abandon the implicit
952754fe60SDimitry Andric // zero denom case for now.
962754fe60SDimitry Andric C.addTransition(stateNotZero);
972754fe60SDimitry Andric }
983b0f4066SDimitry Andric
registerDivZeroChecker(CheckerManager & mgr)993b0f4066SDimitry Andric void ento::registerDivZeroChecker(CheckerManager &mgr) {
1003b0f4066SDimitry Andric mgr.registerChecker<DivZeroChecker>();
1013b0f4066SDimitry Andric }
102