1d99bd55aSTed Kremenek //== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==//
2d99bd55aSTed Kremenek //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d99bd55aSTed Kremenek //
7d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
8d99bd55aSTed Kremenek //
9d99bd55aSTed Kremenek // This defines DivZeroChecker, a builtin check in ExprEngine that performs
10d99bd55aSTed Kremenek // checks for division by zeros.
11d99bd55aSTed Kremenek //
12d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
13d99bd55aSTed Kremenek
1476a21502SKristof Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15*82f3ed99STom Ritter #include "clang/StaticAnalyzer/Checkers/Taint.h"
163a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
176a5674ffSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/Checker.h"
18ae468f77SArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/CheckerManager.h"
19ae468f77SArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20d99bd55aSTed Kremenek
21d99bd55aSTed Kremenek using namespace clang;
22d99bd55aSTed Kremenek using namespace ento;
2344551cf6SArtem Dergachev using namespace taint;
24d99bd55aSTed Kremenek
25d99bd55aSTed Kremenek namespace {
266a5674ffSArgyrios Kyrtzidis class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {
27b8984329SAhmed Charles mutable std::unique_ptr<BuiltinBug> BT;
28e14e591cSHenry Wong void reportBug(const char *Msg, ProgramStateRef StateZero, CheckerContext &C,
29e14e591cSHenry Wong std::unique_ptr<BugReporterVisitor> Visitor = nullptr) const;
30e14e591cSHenry Wong
31d99bd55aSTed Kremenek public:
32ae468f77SArgyrios Kyrtzidis void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
33d99bd55aSTed Kremenek };
34d99bd55aSTed Kremenek } // end anonymous namespace
35d99bd55aSTed Kremenek
getDenomExpr(const ExplodedNode * N)36b2cf0063SGeorge Karpenkov static const Expr *getDenomExpr(const ExplodedNode *N) {
37b2cf0063SGeorge Karpenkov const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
38b2cf0063SGeorge Karpenkov if (const auto *BE = dyn_cast<BinaryOperator>(S))
39b2cf0063SGeorge Karpenkov return BE->getRHS();
40b2cf0063SGeorge Karpenkov return nullptr;
41b2cf0063SGeorge Karpenkov }
42b2cf0063SGeorge Karpenkov
reportBug(const char * Msg,ProgramStateRef StateZero,CheckerContext & C,std::unique_ptr<BugReporterVisitor> Visitor) const43e14e591cSHenry Wong void DivZeroChecker::reportBug(
44e14e591cSHenry Wong const char *Msg, ProgramStateRef StateZero, CheckerContext &C,
45e14e591cSHenry Wong std::unique_ptr<BugReporterVisitor> Visitor) const {
46e39bd407SDevin Coughlin if (ExplodedNode *N = C.generateErrorNode(StateZero)) {
478298af85SAnna Zaks if (!BT)
484aca9b1cSAlexander Kornienko BT.reset(new BuiltinBug(this, "Division by zero"));
498298af85SAnna Zaks
502f169e7cSArtem Dergachev auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
51e14e591cSHenry Wong R->addVisitor(std::move(Visitor));
52b2cf0063SGeorge Karpenkov bugreporter::trackExpressionValue(N, getDenomExpr(N), *R);
538d3a7a56SAaron Ballman C.emitReport(std::move(R));
548298af85SAnna Zaks }
558298af85SAnna Zaks }
568298af85SAnna Zaks
checkPreStmt(const BinaryOperator * B,CheckerContext & C) const57ae468f77SArgyrios Kyrtzidis void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
58ae468f77SArgyrios Kyrtzidis CheckerContext &C) const {
59d99bd55aSTed Kremenek BinaryOperator::Opcode Op = B->getOpcode();
60d99bd55aSTed Kremenek if (Op != BO_Div &&
61d99bd55aSTed Kremenek Op != BO_Rem &&
62d99bd55aSTed Kremenek Op != BO_DivAssign &&
63d99bd55aSTed Kremenek Op != BO_RemAssign)
64d99bd55aSTed Kremenek return;
65d99bd55aSTed Kremenek
668698dd63SAnna Zaks if (!B->getRHS()->getType()->isScalarType())
67d99bd55aSTed Kremenek return;
68d99bd55aSTed Kremenek
69d703ec94SGeorge Karpenkov SVal Denom = C.getSVal(B->getRHS());
7005785d16SDavid Blaikie Optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
71d99bd55aSTed Kremenek
72d99bd55aSTed Kremenek // Divide-by-undefined handled in the generic checking for uses of
73d99bd55aSTed Kremenek // undefined values.
74d99bd55aSTed Kremenek if (!DV)
75d99bd55aSTed Kremenek return;
76d99bd55aSTed Kremenek
77d99bd55aSTed Kremenek // Check for divide by zero.
78d99bd55aSTed Kremenek ConstraintManager &CM = C.getConstraintManager();
7949b1e38eSTed Kremenek ProgramStateRef stateNotZero, stateZero;
80867ea1d4SBenjamin Kramer std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
81d99bd55aSTed Kremenek
820d58033bSAnna Zaks if (!stateNotZero) {
830d58033bSAnna Zaks assert(stateZero);
848298af85SAnna Zaks reportBug("Division by zero", stateZero, C);
858298af85SAnna Zaks return;
86d99bd55aSTed Kremenek }
878298af85SAnna Zaks
8844551cf6SArtem Dergachev bool TaintedD = isTainted(C.getState(), *DV);
898298af85SAnna Zaks if ((stateNotZero && stateZero && TaintedD)) {
90e14e591cSHenry Wong reportBug("Division by a tainted value, possibly zero", stateZero, C,
912b3d49b6SJonas Devlieghere std::make_unique<taint::TaintBugVisitor>(*DV));
92d99bd55aSTed Kremenek return;
93d99bd55aSTed Kremenek }
94d99bd55aSTed Kremenek
95d99bd55aSTed Kremenek // If we get here, then the denom should not be zero. We abandon the implicit
96d99bd55aSTed Kremenek // zero denom case for now.
97da4c8d68SAnna Zaks C.addTransition(stateNotZero);
98d99bd55aSTed Kremenek }
99ae468f77SArgyrios Kyrtzidis
registerDivZeroChecker(CheckerManager & mgr)100ae468f77SArgyrios Kyrtzidis void ento::registerDivZeroChecker(CheckerManager &mgr) {
101ae468f77SArgyrios Kyrtzidis mgr.registerChecker<DivZeroChecker>();
102ae468f77SArgyrios Kyrtzidis }
103058a7a45SKristof Umann
shouldRegisterDivZeroChecker(const CheckerManager & mgr)104bda3dd0dSKirstóf Umann bool ento::shouldRegisterDivZeroChecker(const CheckerManager &mgr) {
105058a7a45SKristof Umann return true;
106058a7a45SKristof Umann }
107