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)