xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This defines DivZeroChecker, a builtin check in ExprEngine that performs
107330f729Sjoerg // checks for division by zeros.
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
137330f729Sjoerg 
147330f729Sjoerg #include "Taint.h"
157330f729Sjoerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
167330f729Sjoerg #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
177330f729Sjoerg #include "clang/StaticAnalyzer/Core/Checker.h"
187330f729Sjoerg #include "clang/StaticAnalyzer/Core/CheckerManager.h"
197330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
207330f729Sjoerg 
217330f729Sjoerg using namespace clang;
227330f729Sjoerg using namespace ento;
237330f729Sjoerg using namespace taint;
247330f729Sjoerg 
257330f729Sjoerg namespace {
267330f729Sjoerg class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {
277330f729Sjoerg   mutable std::unique_ptr<BuiltinBug> BT;
287330f729Sjoerg   void reportBug(const char *Msg, ProgramStateRef StateZero, CheckerContext &C,
297330f729Sjoerg                  std::unique_ptr<BugReporterVisitor> Visitor = nullptr) const;
307330f729Sjoerg 
317330f729Sjoerg public:
327330f729Sjoerg   void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
337330f729Sjoerg };
347330f729Sjoerg } // end anonymous namespace
357330f729Sjoerg 
getDenomExpr(const ExplodedNode * N)367330f729Sjoerg static const Expr *getDenomExpr(const ExplodedNode *N) {
377330f729Sjoerg   const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
387330f729Sjoerg   if (const auto *BE = dyn_cast<BinaryOperator>(S))
397330f729Sjoerg     return BE->getRHS();
407330f729Sjoerg   return nullptr;
417330f729Sjoerg }
427330f729Sjoerg 
reportBug(const char * Msg,ProgramStateRef StateZero,CheckerContext & C,std::unique_ptr<BugReporterVisitor> Visitor) const437330f729Sjoerg void DivZeroChecker::reportBug(
447330f729Sjoerg     const char *Msg, ProgramStateRef StateZero, CheckerContext &C,
457330f729Sjoerg     std::unique_ptr<BugReporterVisitor> Visitor) const {
467330f729Sjoerg   if (ExplodedNode *N = C.generateErrorNode(StateZero)) {
477330f729Sjoerg     if (!BT)
487330f729Sjoerg       BT.reset(new BuiltinBug(this, "Division by zero"));
497330f729Sjoerg 
507330f729Sjoerg     auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
517330f729Sjoerg     R->addVisitor(std::move(Visitor));
527330f729Sjoerg     bugreporter::trackExpressionValue(N, getDenomExpr(N), *R);
537330f729Sjoerg     C.emitReport(std::move(R));
547330f729Sjoerg   }
557330f729Sjoerg }
567330f729Sjoerg 
checkPreStmt(const BinaryOperator * B,CheckerContext & C) const577330f729Sjoerg void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
587330f729Sjoerg                                   CheckerContext &C) const {
597330f729Sjoerg   BinaryOperator::Opcode Op = B->getOpcode();
607330f729Sjoerg   if (Op != BO_Div &&
617330f729Sjoerg       Op != BO_Rem &&
627330f729Sjoerg       Op != BO_DivAssign &&
637330f729Sjoerg       Op != BO_RemAssign)
647330f729Sjoerg     return;
657330f729Sjoerg 
667330f729Sjoerg   if (!B->getRHS()->getType()->isScalarType())
677330f729Sjoerg     return;
687330f729Sjoerg 
697330f729Sjoerg   SVal Denom = C.getSVal(B->getRHS());
707330f729Sjoerg   Optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
717330f729Sjoerg 
727330f729Sjoerg   // Divide-by-undefined handled in the generic checking for uses of
737330f729Sjoerg   // undefined values.
747330f729Sjoerg   if (!DV)
757330f729Sjoerg     return;
767330f729Sjoerg 
777330f729Sjoerg   // Check for divide by zero.
787330f729Sjoerg   ConstraintManager &CM = C.getConstraintManager();
797330f729Sjoerg   ProgramStateRef stateNotZero, stateZero;
807330f729Sjoerg   std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
817330f729Sjoerg 
827330f729Sjoerg   if (!stateNotZero) {
837330f729Sjoerg     assert(stateZero);
847330f729Sjoerg     reportBug("Division by zero", stateZero, C);
857330f729Sjoerg     return;
867330f729Sjoerg   }
877330f729Sjoerg 
887330f729Sjoerg   bool TaintedD = isTainted(C.getState(), *DV);
897330f729Sjoerg   if ((stateNotZero && stateZero && TaintedD)) {
907330f729Sjoerg     reportBug("Division by a tainted value, possibly zero", stateZero, C,
917330f729Sjoerg               std::make_unique<taint::TaintBugVisitor>(*DV));
927330f729Sjoerg     return;
937330f729Sjoerg   }
947330f729Sjoerg 
957330f729Sjoerg   // If we get here, then the denom should not be zero. We abandon the implicit
967330f729Sjoerg   // zero denom case for now.
977330f729Sjoerg   C.addTransition(stateNotZero);
987330f729Sjoerg }
997330f729Sjoerg 
registerDivZeroChecker(CheckerManager & mgr)1007330f729Sjoerg void ento::registerDivZeroChecker(CheckerManager &mgr) {
1017330f729Sjoerg   mgr.registerChecker<DivZeroChecker>();
1027330f729Sjoerg }
1037330f729Sjoerg 
shouldRegisterDivZeroChecker(const CheckerManager & mgr)104*e038c9c4Sjoerg bool ento::shouldRegisterDivZeroChecker(const CheckerManager &mgr) {
1057330f729Sjoerg   return true;
1067330f729Sjoerg }
107