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