brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.8 KiB · ab90615 Raw
140 lines · cpp
1//== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This defines DivZeroChecker, a builtin check in ExprEngine that performs10// checks for division by zeros.11//12//===----------------------------------------------------------------------===//13 14#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"15#include "clang/StaticAnalyzer/Checkers/Taint.h"16#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"17#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"18#include "clang/StaticAnalyzer/Core/Checker.h"19#include "clang/StaticAnalyzer/Core/CheckerManager.h"20#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"21#include <optional>22 23using namespace clang;24using namespace ento;25using namespace taint;26 27namespace {28class DivZeroChecker : public CheckerFamily<check::PreStmt<BinaryOperator>> {29  void reportBug(StringRef Msg, ProgramStateRef StateZero,30                 CheckerContext &C) const;31  void reportTaintBug(StringRef Msg, ProgramStateRef StateZero,32                      CheckerContext &C,33                      llvm::ArrayRef<SymbolRef> TaintedSyms) const;34 35public:36  /// This checker family implements two user-facing checker parts.37  CheckerFrontendWithBugType DivideZeroChecker{"Division by zero"};38  CheckerFrontendWithBugType TaintedDivChecker{"Division by zero",39                                               categories::TaintedData};40 41  void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;42 43  /// Identifies this checker family for debugging purposes.44  StringRef getDebugTag() const override { return "DivZeroChecker"; }45};46} // end anonymous namespace47 48static const Expr *getDenomExpr(const ExplodedNode *N) {49  const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();50  if (const auto *BE = dyn_cast<BinaryOperator>(S))51    return BE->getRHS();52  return nullptr;53}54 55void DivZeroChecker::reportBug(StringRef Msg, ProgramStateRef StateZero,56                               CheckerContext &C) const {57  if (!DivideZeroChecker.isEnabled())58    return;59  if (ExplodedNode *N = C.generateErrorNode(StateZero)) {60    auto R =61        std::make_unique<PathSensitiveBugReport>(DivideZeroChecker, Msg, N);62    bugreporter::trackExpressionValue(N, getDenomExpr(N), *R);63    C.emitReport(std::move(R));64  }65}66 67void DivZeroChecker::reportTaintBug(68    StringRef Msg, ProgramStateRef StateZero, CheckerContext &C,69    llvm::ArrayRef<SymbolRef> TaintedSyms) const {70  if (!TaintedDivChecker.isEnabled())71    return;72  if (ExplodedNode *N = C.generateErrorNode(StateZero)) {73    auto R =74        std::make_unique<PathSensitiveBugReport>(TaintedDivChecker, Msg, N);75    bugreporter::trackExpressionValue(N, getDenomExpr(N), *R);76    for (auto Sym : TaintedSyms)77      R->markInteresting(Sym);78    C.emitReport(std::move(R));79  }80}81 82void DivZeroChecker::checkPreStmt(const BinaryOperator *B,83                                  CheckerContext &C) const {84  BinaryOperator::Opcode Op = B->getOpcode();85  if (Op != BO_Div &&86      Op != BO_Rem &&87      Op != BO_DivAssign &&88      Op != BO_RemAssign)89    return;90 91  if (!B->getRHS()->getType()->isScalarType())92    return;93 94  SVal Denom = C.getSVal(B->getRHS());95  std::optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();96 97  // Divide-by-undefined handled in the generic checking for uses of98  // undefined values.99  if (!DV)100    return;101 102  // Check for divide by zero.103  ConstraintManager &CM = C.getConstraintManager();104  ProgramStateRef stateNotZero, stateZero;105  std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);106 107  if (!stateNotZero) {108    assert(stateZero);109    reportBug("Division by zero", stateZero, C);110    return;111  }112 113  if ((stateNotZero && stateZero)) {114    std::vector<SymbolRef> taintedSyms = getTaintedSymbols(C.getState(), *DV);115    if (!taintedSyms.empty()) {116      reportTaintBug("Division by a tainted value, possibly zero", stateZero, C,117                     taintedSyms);118      // Fallthrough to continue analysis in case of non-zero denominator.119    }120  }121 122  // If we get here, then the denom should not be zero. We abandon the implicit123  // zero denom case for now.124  C.addTransition(stateNotZero);125}126 127void ento::registerDivZeroChecker(CheckerManager &Mgr) {128  Mgr.getChecker<DivZeroChecker>()->DivideZeroChecker.enable(Mgr);129}130 131bool ento::shouldRegisterDivZeroChecker(const CheckerManager &) { return true; }132 133void ento::registerTaintedDivChecker(CheckerManager &Mgr) {134  Mgr.getChecker<DivZeroChecker>()->TaintedDivChecker.enable(Mgr);135}136 137bool ento::shouldRegisterTaintedDivChecker(const CheckerManager &) {138  return true;139}140