Path: blob/main/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
35269 views
//== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This defines DivZeroChecker, a builtin check in ExprEngine that performs9// checks for division by zeros.10//11//===----------------------------------------------------------------------===//1213#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"14#include "clang/StaticAnalyzer/Checkers/Taint.h"15#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"16#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"17#include "clang/StaticAnalyzer/Core/Checker.h"18#include "clang/StaticAnalyzer/Core/CheckerManager.h"19#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"20#include <optional>2122using namespace clang;23using namespace ento;24using namespace taint;2526namespace {27class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {28const BugType BT{this, "Division by zero"};29const BugType TaintBT{this, "Division by zero", categories::TaintedData};30void reportBug(StringRef Msg, ProgramStateRef StateZero,31CheckerContext &C) const;32void reportTaintBug(StringRef Msg, ProgramStateRef StateZero,33CheckerContext &C,34llvm::ArrayRef<SymbolRef> TaintedSyms) const;3536public:37void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;38};39} // end anonymous namespace4041static const Expr *getDenomExpr(const ExplodedNode *N) {42const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();43if (const auto *BE = dyn_cast<BinaryOperator>(S))44return BE->getRHS();45return nullptr;46}4748void DivZeroChecker::reportBug(StringRef Msg, ProgramStateRef StateZero,49CheckerContext &C) const {50if (ExplodedNode *N = C.generateErrorNode(StateZero)) {51auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);52bugreporter::trackExpressionValue(N, getDenomExpr(N), *R);53C.emitReport(std::move(R));54}55}5657void DivZeroChecker::reportTaintBug(58StringRef Msg, ProgramStateRef StateZero, CheckerContext &C,59llvm::ArrayRef<SymbolRef> TaintedSyms) const {60if (ExplodedNode *N = C.generateErrorNode(StateZero)) {61auto R = std::make_unique<PathSensitiveBugReport>(TaintBT, Msg, N);62bugreporter::trackExpressionValue(N, getDenomExpr(N), *R);63for (auto Sym : TaintedSyms)64R->markInteresting(Sym);65C.emitReport(std::move(R));66}67}6869void DivZeroChecker::checkPreStmt(const BinaryOperator *B,70CheckerContext &C) const {71BinaryOperator::Opcode Op = B->getOpcode();72if (Op != BO_Div &&73Op != BO_Rem &&74Op != BO_DivAssign &&75Op != BO_RemAssign)76return;7778if (!B->getRHS()->getType()->isScalarType())79return;8081SVal Denom = C.getSVal(B->getRHS());82std::optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();8384// Divide-by-undefined handled in the generic checking for uses of85// undefined values.86if (!DV)87return;8889// Check for divide by zero.90ConstraintManager &CM = C.getConstraintManager();91ProgramStateRef stateNotZero, stateZero;92std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);9394if (!stateNotZero) {95assert(stateZero);96reportBug("Division by zero", stateZero, C);97return;98}99100if ((stateNotZero && stateZero)) {101std::vector<SymbolRef> taintedSyms = getTaintedSymbols(C.getState(), *DV);102if (!taintedSyms.empty()) {103reportTaintBug("Division by a tainted value, possibly zero", stateZero, C,104taintedSyms);105return;106}107}108109// If we get here, then the denom should not be zero. We abandon the implicit110// zero denom case for now.111C.addTransition(stateNotZero);112}113114void ento::registerDivZeroChecker(CheckerManager &mgr) {115mgr.registerChecker<DivZeroChecker>();116}117118bool ento::shouldRegisterDivZeroChecker(const CheckerManager &mgr) {119return true;120}121122123