1f4a2713aSLionel Sambuc //== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // This defines DivZeroChecker, a builtin check in ExprEngine that performs
11f4a2713aSLionel Sambuc // checks for division by zeros.
12f4a2713aSLionel Sambuc //
13f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
14f4a2713aSLionel Sambuc
15f4a2713aSLionel Sambuc #include "ClangSACheckers.h"
16f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/Checker.h"
18f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/CheckerManager.h"
19f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20f4a2713aSLionel Sambuc
21f4a2713aSLionel Sambuc using namespace clang;
22f4a2713aSLionel Sambuc using namespace ento;
23f4a2713aSLionel Sambuc
24f4a2713aSLionel Sambuc namespace {
25f4a2713aSLionel Sambuc class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {
26*0a6a1f1dSLionel Sambuc mutable std::unique_ptr<BuiltinBug> BT;
27f4a2713aSLionel Sambuc void reportBug(const char *Msg,
28f4a2713aSLionel Sambuc ProgramStateRef StateZero,
29f4a2713aSLionel Sambuc CheckerContext &C) const ;
30f4a2713aSLionel Sambuc public:
31f4a2713aSLionel Sambuc void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
32f4a2713aSLionel Sambuc };
33f4a2713aSLionel Sambuc } // end anonymous namespace
34f4a2713aSLionel Sambuc
reportBug(const char * Msg,ProgramStateRef StateZero,CheckerContext & C) const35f4a2713aSLionel Sambuc void DivZeroChecker::reportBug(const char *Msg,
36f4a2713aSLionel Sambuc ProgramStateRef StateZero,
37f4a2713aSLionel Sambuc CheckerContext &C) const {
38f4a2713aSLionel Sambuc if (ExplodedNode *N = C.generateSink(StateZero)) {
39f4a2713aSLionel Sambuc if (!BT)
40*0a6a1f1dSLionel Sambuc BT.reset(new BuiltinBug(this, "Division by zero"));
41f4a2713aSLionel Sambuc
42f4a2713aSLionel Sambuc BugReport *R = new BugReport(*BT, Msg, N);
43f4a2713aSLionel Sambuc bugreporter::trackNullOrUndefValue(N, bugreporter::GetDenomExpr(N), *R);
44f4a2713aSLionel Sambuc C.emitReport(R);
45f4a2713aSLionel Sambuc }
46f4a2713aSLionel Sambuc }
47f4a2713aSLionel Sambuc
checkPreStmt(const BinaryOperator * B,CheckerContext & C) const48f4a2713aSLionel Sambuc void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
49f4a2713aSLionel Sambuc CheckerContext &C) const {
50f4a2713aSLionel Sambuc BinaryOperator::Opcode Op = B->getOpcode();
51f4a2713aSLionel Sambuc if (Op != BO_Div &&
52f4a2713aSLionel Sambuc Op != BO_Rem &&
53f4a2713aSLionel Sambuc Op != BO_DivAssign &&
54f4a2713aSLionel Sambuc Op != BO_RemAssign)
55f4a2713aSLionel Sambuc return;
56f4a2713aSLionel Sambuc
57f4a2713aSLionel Sambuc if (!B->getRHS()->getType()->isScalarType())
58f4a2713aSLionel Sambuc return;
59f4a2713aSLionel Sambuc
60f4a2713aSLionel Sambuc SVal Denom = C.getState()->getSVal(B->getRHS(), C.getLocationContext());
61f4a2713aSLionel Sambuc Optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
62f4a2713aSLionel Sambuc
63f4a2713aSLionel Sambuc // Divide-by-undefined handled in the generic checking for uses of
64f4a2713aSLionel Sambuc // undefined values.
65f4a2713aSLionel Sambuc if (!DV)
66f4a2713aSLionel Sambuc return;
67f4a2713aSLionel Sambuc
68f4a2713aSLionel Sambuc // Check for divide by zero.
69f4a2713aSLionel Sambuc ConstraintManager &CM = C.getConstraintManager();
70f4a2713aSLionel Sambuc ProgramStateRef stateNotZero, stateZero;
71*0a6a1f1dSLionel Sambuc std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
72f4a2713aSLionel Sambuc
73f4a2713aSLionel Sambuc if (!stateNotZero) {
74f4a2713aSLionel Sambuc assert(stateZero);
75f4a2713aSLionel Sambuc reportBug("Division by zero", stateZero, C);
76f4a2713aSLionel Sambuc return;
77f4a2713aSLionel Sambuc }
78f4a2713aSLionel Sambuc
79f4a2713aSLionel Sambuc bool TaintedD = C.getState()->isTainted(*DV);
80f4a2713aSLionel Sambuc if ((stateNotZero && stateZero && TaintedD)) {
81f4a2713aSLionel Sambuc reportBug("Division by a tainted value, possibly zero", stateZero, C);
82f4a2713aSLionel Sambuc return;
83f4a2713aSLionel Sambuc }
84f4a2713aSLionel Sambuc
85f4a2713aSLionel Sambuc // If we get here, then the denom should not be zero. We abandon the implicit
86f4a2713aSLionel Sambuc // zero denom case for now.
87f4a2713aSLionel Sambuc C.addTransition(stateNotZero);
88f4a2713aSLionel Sambuc }
89f4a2713aSLionel Sambuc
registerDivZeroChecker(CheckerManager & mgr)90f4a2713aSLionel Sambuc void ento::registerDivZeroChecker(CheckerManager &mgr) {
91f4a2713aSLionel Sambuc mgr.registerChecker<DivZeroChecker>();
92f4a2713aSLionel Sambuc }
93