DivZeroChecker.cpp revision 23c5497d36cbf0506f48575b6d89abb4dde1b5dc
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==//
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                     The LLVM Compiler Infrastructure
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file is distributed under the University of Illinois Open Source
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// License. See LICENSE.TXT for details.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===//
97d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// This defines DivZeroChecker, a builtin check in ExprEngine that performs
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// checks for division by zeros.
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)//
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===//
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ClangSACheckers.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/Checker.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/CheckerManager.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace clang;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace ento;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mutable llvm::OwningPtr<BuiltinBug> BT;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public:
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // end anonymous namespace
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  CheckerContext &C) const {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BinaryOperator::Opcode Op = B->getOpcode();
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (Op != BO_Div &&
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Op != BO_Rem &&
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Op != BO_DivAssign &&
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Op != BO_RemAssign)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!B->getRHS()->getType()->isIntegerType() ||
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !B->getRHS()->getType()->isScalarType())
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SVal Denom = C.getState()->getSVal(B->getRHS());
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Divide-by-undefined handled in the generic checking for uses of
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // undefined values.
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!DV)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check for divide by zero.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConstraintManager &CM = C.getConstraintManager();
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ProgramState *stateNotZero, *stateZero;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  llvm::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (stateZero && !stateNotZero) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ExplodedNode *N = C.generateSink(stateZero)) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!BT)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BT.reset(new BuiltinBug("Division by zero"));
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BugReport *R =
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new BugReport(*BT, BT->getDescription(), N);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   bugreporter::GetDenomExpr(N)));
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      C.EmitReport(R);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we get here, then the denom should not be zero. We abandon the implicit
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // zero denom case for now.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  C.addTransition(stateNotZero);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ento::registerDivZeroChecker(CheckerManager &mgr) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mgr.registerChecker<DivZeroChecker>();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)