DivZeroChecker.cpp revision 296417
193142Sru//== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==//
242664Smarkm//
393142Sru//                     The LLVM Compiler Infrastructure
421495Sjmacd//
593142Sru// This file is distributed under the University of Illinois Open Source
642664Smarkm// License. See LICENSE.TXT for details.
721495Sjmacd//
821495Sjmacd//===----------------------------------------------------------------------===//
921495Sjmacd//
1021495Sjmacd// This defines DivZeroChecker, a builtin check in ExprEngine that performs
1121495Sjmacd// checks for division by zeros.
1221495Sjmacd//
1321495Sjmacd//===----------------------------------------------------------------------===//
1421495Sjmacd
1521495Sjmacd#include "ClangSACheckers.h"
1621495Sjmacd#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
1721495Sjmacd#include "clang/StaticAnalyzer/Core/Checker.h"
1821495Sjmacd#include "clang/StaticAnalyzer/Core/CheckerManager.h"
1921495Sjmacd#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
2021495Sjmacd
2121495Sjmacdusing namespace clang;
2221495Sjmacdusing namespace ento;
2321495Sjmacd
2442664Smarkmnamespace {
2521495Sjmacdclass DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {
2621495Sjmacd  mutable std::unique_ptr<BuiltinBug> BT;
2721495Sjmacd  void reportBug(const char *Msg,
2842664Smarkm                 ProgramStateRef StateZero,
2942664Smarkm                 CheckerContext &C) const ;
3021495Sjmacdpublic:
3121495Sjmacd  void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
3242664Smarkm};
3342664Smarkm} // end anonymous namespace
3442664Smarkm
3542664Smarkmvoid DivZeroChecker::reportBug(const char *Msg,
3642664Smarkm                               ProgramStateRef StateZero,
3742664Smarkm                               CheckerContext &C) const {
3842664Smarkm  if (ExplodedNode *N = C.generateErrorNode(StateZero)) {
3942664Smarkm    if (!BT)
4042664Smarkm      BT.reset(new BuiltinBug(this, "Division by zero"));
4121495Sjmacd
4242664Smarkm    auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
4342664Smarkm    bugreporter::trackNullOrUndefValue(N, bugreporter::GetDenomExpr(N), *R);
4442664Smarkm    C.emitReport(std::move(R));
4542664Smarkm  }
4621495Sjmacd}
4721495Sjmacd
4821495Sjmacdvoid DivZeroChecker::checkPreStmt(const BinaryOperator *B,
4942664Smarkm                                  CheckerContext &C) const {
5042664Smarkm  BinaryOperator::Opcode Op = B->getOpcode();
5121495Sjmacd  if (Op != BO_Div &&
5221495Sjmacd      Op != BO_Rem &&
5321495Sjmacd      Op != BO_DivAssign &&
5421495Sjmacd      Op != BO_RemAssign)
5521495Sjmacd    return;
5621495Sjmacd
5721495Sjmacd  if (!B->getRHS()->getType()->isScalarType())
5821495Sjmacd    return;
5921495Sjmacd
6021495Sjmacd  SVal Denom = C.getState()->getSVal(B->getRHS(), C.getLocationContext());
6121495Sjmacd  Optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
6221495Sjmacd
6321495Sjmacd  // Divide-by-undefined handled in the generic checking for uses of
6421495Sjmacd  // undefined values.
6521495Sjmacd  if (!DV)
6621495Sjmacd    return;
6721495Sjmacd
6821495Sjmacd  // Check for divide by zero.
6921495Sjmacd  ConstraintManager &CM = C.getConstraintManager();
7021495Sjmacd  ProgramStateRef stateNotZero, stateZero;
7121495Sjmacd  std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
7221495Sjmacd
7321495Sjmacd  if (!stateNotZero) {
7442664Smarkm    assert(stateZero);
7542664Smarkm    reportBug("Division by zero", stateZero, C);
7642664Smarkm    return;
7721495Sjmacd  }
7821495Sjmacd
7921495Sjmacd  bool TaintedD = C.getState()->isTainted(*DV);
8056164Sru  if ((stateNotZero && stateZero && TaintedD)) {
8156164Sru    reportBug("Division by a tainted value, possibly zero", stateZero, C);
8256164Sru    return;
8356164Sru  }
8421495Sjmacd
8521495Sjmacd  // If we get here, then the denom should not be zero. We abandon the implicit
8621495Sjmacd  // zero denom case for now.
8721495Sjmacd  C.addTransition(stateNotZero);
8821495Sjmacd}
8921495Sjmacd
9042664Smarkmvoid ento::registerDivZeroChecker(CheckerManager &mgr) {
9142664Smarkm  mgr.registerChecker<DivZeroChecker>();
9221495Sjmacd}
9321495Sjmacd